Hone logo
Hone
Problems

Vue 3 Composition API: Reusable Button Component with h Function

This challenge focuses on mastering the h function within Vue 3's Composition API to create a flexible and reusable button component. Understanding how to programmatically construct Virtual DOM nodes with h is a powerful technique for building complex UIs and highly dynamic components.

Problem Description

You are tasked with creating a reusable Button component in Vue 3 using TypeScript and the Composition API. Instead of relying on standard Vue template syntax for rendering, you will exclusively use the h function to define the component's structure. This component should accept various props to customize its appearance and behavior, such as text content, click handlers, and styling.

Key Requirements:

  • Use h for Rendering: The entire rendering logic of the Button component must be implemented using the h function from vue.
  • Props for Customization: The component should accept the following props:
    • text: A string representing the button's label.
    • onClick: An optional Function to be called when the button is clicked.
    • disabled: An optional boolean to disable the button.
    • variant: An optional string that can be 'primary' or 'secondary', influencing the button's styling.
  • Dynamic Styling: The variant prop should dynamically apply CSS classes to the button. For example, 'primary' might add a btn-primary class, and 'secondary' a btn-secondary class.
  • Event Handling: The onClick prop should be correctly attached to the button's click event.
  • Disabled State: The disabled prop should correctly set the disabled attribute on the HTML button element.
  • TypeScript Support: The component should be written in TypeScript, with proper type definitions for props.

Expected Behavior:

A rendered button component should display the provided text. Clicking the button should trigger the onClick function if provided. If disabled is true, the button should be visually and functionally disabled, and the onClick handler should not be triggered. The variant prop should add corresponding CSS classes for styling.

Edge Cases to Consider:

  • No onClick handler is provided.
  • No variant is provided (default styling should apply or no specific variant class).
  • A variant other than 'primary' or 'secondary' is provided (the component should handle this gracefully, perhaps by ignoring it or applying a default).

Examples

Example 1: Basic Button

// In your parent component (e.g., App.vue)
import { defineComponent, h } from 'vue';
import Button from './Button.vue'; // Assuming Button.vue is in the same directory

export default defineComponent({
  setup() {
    const handleClick = () => {
      alert('Button clicked!');
    };

    return () => h(Button, { text: 'Click Me', onClick: handleClick });
  },
});

Output: A button element with the text "Click Me". Clicking it will trigger an alert.

Example 2: Disabled Primary Button

// In your parent component
import { defineComponent, h } from 'vue';
import Button from './Button.vue';

export default defineComponent({
  setup() {
    return () => h(Button, { text: 'Disabled Button', onClick: () => {}, disabled: true, variant: 'primary' });
  },
});

Output: A visually disabled button element with the text "Disabled Button". Clicking it will have no effect. It should also have a btn-primary class applied.

Example 3: Secondary Button with No Click Handler

// In your parent component
import { defineComponent, h } from 'vue';
import Button from './Button.vue';

export default defineComponent({
  setup() {
    return () => h(Button, { text: 'Info', variant: 'secondary' });
  },
});

Output: A button element with the text "Info" and a btn-secondary class applied. Clicking it will have no observable effect as no onClick handler is provided.

Constraints

  • Vue.js version: 3.x
  • Language: TypeScript
  • Rendering exclusively via the h function. No <template> block is allowed within the Button component itself.
  • The Button component should be a functional component (or a defineComponent with setup returning a render function).
  • CSS classes for variants should be simple strings (e.g., btn-primary). You do not need to provide the actual CSS styles, just the class names.

Notes

  • Remember that the h function takes three arguments: the tag name or component definition, an object of attributes (props, event listeners, DOM attributes), and children (an array of VNodes or a string).
  • Consider how to handle the disabled attribute and onClick event listener correctly within the attributes object passed to h.
  • For styling, simply add the appropriate CSS class names to the attributes object.
  • This exercise is about understanding how to build components programmatically with h, which is fundamental for advanced Vue patterns and plugins.
Loading editor...
typescript