Create a Reusable Badge Component in React
This challenge asks you to build a flexible and reusable Badge component in React using TypeScript. A badge component is a common UI element used to display labels, tags, or status indicators. A well-built badge component should be customizable in terms of its content, appearance, and interactivity.
Problem Description
You need to create a React functional component named Badge that accepts various props to define its behavior and styling. The primary goal is to make this component highly adaptable to different use cases.
Key Requirements:
- Content: The
Badgecomponent should accept arbitrary React nodes as its content. This allows for text, icons, or other complex elements within the badge. - Appearance Customization:
- Color/Variant: Allow users to specify a
variantprop (e.g., 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark') to control the badge's background and text color. - Pill Shape: Provide a
pillprop (boolean) to render the badge with fully rounded corners (pill shape). - Size: Allow for different
sizeoptions (e.g., 'sm', 'md', 'lg') to control the padding and font size.
- Color/Variant: Allow users to specify a
- Interactivity (Optional but Recommended):
- Dismissible: Include an optional
onDismissprop. If provided, a close button (e.g., an 'x' icon) should appear on the badge, and clicking it should trigger theonDismisscallback function.
- Dismissible: Include an optional
- Accessibility: Ensure the component is accessible. For example, if it's dismissible, the close button should be focusable and triggerable via keyboard.
- TypeScript: Implement the component and its props using TypeScript for type safety.
Expected Behavior:
- A badge with text "New" and
variant="primary"should display a primary-colored background with contrasting text. - A badge with text "JavaScript" and
pill={true}should be a rounded pill shape with default styling. - A badge with text "Success" and
variant="success"andsize="lg"should be a large success-themed badge. - A badge with text "Draft" and
onDismiss={() => console.log('Badge dismissed')}should render a dismissible badge. Clicking the close button should call the provided callback.
Edge Cases:
- What happens if no
variantorsizeis provided? (Should fall back to sensible defaults). - What happens if
onDismissis provided but no content is rendered? - How should the component handle very long content? (Consider overflow and text wrapping).
Examples
Example 1: Basic Badge
// Props:
const badgeProps = {
children: "New",
variant: "primary" as const, // Use 'as const' for literal type
};
// Expected rendered HTML (conceptual):
// <span class="badge badge-primary">New</span>
Explanation: Renders a basic badge with the text "New" styled with the primary color scheme.
Example 2: Pill Badge with Size
// Props:
const badgeProps = {
children: "JavaScript",
pill: true,
size: "md" as const,
};
// Expected rendered HTML (conceptual):
// <span class="badge badge-pill badge-md">JavaScript</span>
Explanation: Renders a pill-shaped badge with "JavaScript" as content, using the medium size styling.
Example 3: Dismissible Badge
// Props:
const badgeProps = {
children: "Draft",
variant: "warning" as const,
onDismiss: () => alert("Badge dismissed!"),
};
// Expected rendered HTML (conceptual):
// <span class="badge badge-warning">
// Draft
// <button class="badge-dismiss-btn" aria-label="Dismiss badge">
// ×
// </button>
// </span>
Explanation: Renders a warning-themed badge with the text "Draft". It includes a dismiss button. Clicking the button will trigger the alert("Badge dismissed!") function.
Constraints
- The component should be implemented as a functional component.
- All props should be clearly defined using TypeScript interfaces.
- Styling should be achievable using CSS classes (you don't need to write the CSS, but the component should render appropriate class names). Assume a CSS framework or a separate CSS file will handle the actual styling based on these classes.
- The component should be efficient and render quickly.
variantprop should accept a union of string literals:'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark'.sizeprop should accept a union of string literals:'sm' | 'md' | 'lg'.
Notes
- Consider using a default value for
variantandsizeto ensure a reasonable default appearance if these props are not provided. - For the dismissible button, consider using an
aria-labelfor accessibility. - Think about how to structure your component's JSX to efficiently render the different states (e.g., with or without a dismiss button).
- The challenge is focused on the component's structure, props, and TypeScript definition. You do not need to implement the actual CSS styling. Assume class names like
badge,badge-primary,badge-pill,badge-sm,badge-dismiss-btnwill be available for styling.