Hone logo
Hone
Problems

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:

  1. Content: The Badge component should accept arbitrary React nodes as its content. This allows for text, icons, or other complex elements within the badge.
  2. Appearance Customization:
    • Color/Variant: Allow users to specify a variant prop (e.g., 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark') to control the badge's background and text color.
    • Pill Shape: Provide a pill prop (boolean) to render the badge with fully rounded corners (pill shape).
    • Size: Allow for different size options (e.g., 'sm', 'md', 'lg') to control the padding and font size.
  3. Interactivity (Optional but Recommended):
    • Dismissible: Include an optional onDismiss prop. If provided, a close button (e.g., an 'x' icon) should appear on the badge, and clicking it should trigger the onDismiss callback function.
  4. Accessibility: Ensure the component is accessible. For example, if it's dismissible, the close button should be focusable and triggerable via keyboard.
  5. 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" and size="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 variant or size is provided? (Should fall back to sensible defaults).
  • What happens if onDismiss is 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">
//     &times;
//   </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.
  • variant prop should accept a union of string literals: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark'.
  • size prop should accept a union of string literals: 'sm' | 'md' | 'lg'.

Notes

  • Consider using a default value for variant and size to ensure a reasonable default appearance if these props are not provided.
  • For the dismissible button, consider using an aria-label for 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-btn will be available for styling.
Loading editor...
typescript