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
hfor Rendering: The entire rendering logic of theButtoncomponent must be implemented using thehfunction fromvue. - Props for Customization: The component should accept the following props:
text: Astringrepresenting the button's label.onClick: An optionalFunctionto be called when the button is clicked.disabled: An optionalbooleanto disable the button.variant: An optionalstringthat can be'primary'or'secondary', influencing the button's styling.
- Dynamic Styling: The
variantprop should dynamically apply CSS classes to the button. For example,'primary'might add abtn-primaryclass, and'secondary'abtn-secondaryclass. - Event Handling: The
onClickprop should be correctly attached to the button's click event. - Disabled State: The
disabledprop should correctly set thedisabledattribute 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
onClickhandler is provided. - No
variantis provided (default styling should apply or no specific variant class). - A
variantother 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
hfunction. No<template>block is allowed within theButtoncomponent itself. - The
Buttoncomponent should be a functional component (or adefineComponentwithsetupreturning 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
hfunction 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
disabledattribute andonClickevent listener correctly within the attributes object passed toh. - 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.