Customizable Button Component with Variants in React
This challenge focuses on building a reusable Button component in React using TypeScript. The goal is to create a flexible component that can be styled and behave differently based on predefined "variants" (e.g., primary, secondary, danger). This is a fundamental building block for many UI libraries and applications, promoting consistency and maintainability.
Problem Description
You need to create a React functional component named Button that accepts various props to control its appearance and behavior. The core requirement is to implement "variants" that allow the button to be rendered with different styles.
Key Requirements:
- Component Structure: The
Buttoncomponent should render a native HTML<button>element. - Variant Prop: It must accept a
variantprop, which can be one of the following string literals:'primary','secondary','outline','danger'. - Children Prop: It should accept a
childrenprop to render the button's content (text, icons, etc.). - Click Handler: It must accept an
onClickprop for handling click events. - Disabled State: It should support a
disabledboolean prop to disable the button. - Styling: The variants should apply distinct visual styles. For this challenge, focus on applying different background colors, text colors, and border styles based on the
variantprop. You can use CSS Modules, styled-components, or inline styles for this. - TypeScript Support: All props and the component itself must be strongly typed using TypeScript.
Expected Behavior:
- When
variantis'primary', the button should have a distinct primary color background and contrasting text. - When
variantis'secondary', it should have a different, less prominent background color. - When
variantis'outline', it should have a transparent background with a colored border. - When
variantis'danger', it should have a red background and white text. - A disabled button should have a visually distinct style (e.g., muted colors,
cursor: not-allowed) and should not triggeronClickevents. - The
childrenprop should be rendered correctly within the button.
Edge Cases:
- What happens if no
variantis provided? (Consider a sensible default). - How should the
disabledprop interact with thevariantstyles?
Examples
Example 1: Primary Button
<Button variant="primary" onClick={() => console.log('Primary clicked!')}>
Click Me
</Button>
Output: A button with a primary background color, white text, and "Click Me" inside. Clicking it logs "Primary clicked!".
Example 2: Outline Button
<Button variant="outline" onClick={() => console.log('Outline clicked!')}>
Learn More
</Button>
Output: A button with a transparent background, a colored border, and "Learn More" inside. Clicking it logs "Outline clicked!".
Example 3: Disabled Danger Button
<Button variant="danger" onClick={() => console.log('Danger clicked!')} disabled>
Delete Item
</Button>
Output: A button with a muted red background, likely greyed out text, and a not-allowed cursor. It visually appears disabled and does not trigger the onClick handler.
Constraints
- The
Buttoncomponent must be a functional component. - The
variantprop must be one of the specified string literals. - The
onClickprop should accept a function with an event argument, or be optional. - The
disabledprop must be a boolean. - The solution should be implemented in TypeScript.
- Styling should be applied clearly to differentiate variants and the disabled state.
Notes
- Consider defining a type for your
variantprop to ensure type safety. - Think about a default
variantif none is provided. - When styling the disabled state, ensure it's visually distinct from active states across all variants.
- You can use any styling method you prefer (CSS Modules, styled-components, Tailwind CSS, inline styles) as long as the requirements are met and the code is well-organized.