Implement a Reusable Chip Component in React with TypeScript
This challenge requires you to build a versatile "Chip" component in React using TypeScript. Chips are commonly used in UI design to represent distinct pieces of information, such as tags, filters, or user avatars. A well-implemented chip component should be configurable, accessible, and visually appealing.
Problem Description
You need to create a React functional component named Chip that accepts various props to customize its appearance and behavior. The Chip component should be able to display text and optionally an icon. It should also support interactive states like hover and focus, and allow for an optional close button.
Key Requirements:
- Basic Rendering: The
Chipcomponent must render adivelement that visually represents a chip. - Text Content: It should accept a
labelprop (string) to display as the chip's text. - Icon Support: An optional
iconprop should be supported, which can accept a React node (e.g., an SVG component or an<img>tag) to be displayed before the label. - Closable Chips: A
closableprop (boolean) should determine if a close button (e.g., an 'x' icon) is rendered next to the label. - On Close Handler: If
closableis true, anonCloseprop (function) must be provided. This function should be called when the close button is clicked. - Styling: The component should have basic styling applied to make it look like a chip (e.g., rounded corners, padding). You can use CSS Modules, styled-components, or inline styles.
- Accessibility:
- The chip should be focusable.
- If closable, the close button should be a distinct interactive element with appropriate ARIA attributes.
- TypeScript: The component and its props must be defined using TypeScript for strong typing.
Expected Behavior:
- A chip with only a
labelshould render the text. - A chip with
labelandiconshould render the icon followed by the text. - A chip with
labelandclosable={true}should render the label and a close button. - Clicking the close button on a closable chip should trigger the
onClosefunction. - The component should visually indicate hover and focus states.
Edge Cases to Consider:
- What happens if
closableis true butonCloseis not provided? (Consider how to handle this, perhaps with a console warning or by disabling the close button). - Rendering an empty label.
- Rendering a very long label (consider truncation or wrapping).
Examples
Example 1: Basic Chip
// Props passed to the Chip component
const chipProps = {
label: "React Tag",
};
// Expected rendered output (conceptual, actual HTML structure might vary based on styling)
// <div class="chip">React Tag</div>
Explanation: A simple chip with only a text label.
Example 2: Chip with Icon
import { StarIcon } from './icons'; // Assuming you have an icon component
const chipProps = {
label: "Featured",
icon: <StarIcon />,
};
// Expected rendered output
// <div class="chip">
// <span class="chip-icon"><StarIcon /></span>
// <span class="chip-label">Featured</span>
// </div>
Explanation: A chip displaying an icon before its text label.
Example 3: Closable Chip
const handleClose = () => {
console.log("Chip closed!");
};
const chipProps = {
label: "Filter Option",
closable: true,
onClose: handleClose,
};
// Expected rendered output
// <div class="chip">
// <span class="chip-label">Filter Option</span>
// <button class="chip-close-button" aria-label="Close chip">
// ×
// </button>
// </div>
Explanation: A chip with a label and a close button. Clicking the button calls the onClose handler.
Example 4: Chip with Icon and Close Button
import { UserIcon } from './icons';
const handleClose = () => {
console.log("User chip closed!");
};
const chipProps = {
label: "John Doe",
icon: <UserIcon />,
closable: true,
onClose: handleClose,
};
// Expected rendered output
// <div class="chip">
// <span class="chip-icon"><UserIcon /></span>
// <span class="chip-label">John Doe</span>
// <button class="chip-close-button" aria-label="Close chip">
// ×
// </button>
// </div>
Explanation: A chip combining an icon, text, and a close button.
Constraints
- The
Chipcomponent must be a React functional component. - All prop types must be explicitly defined using TypeScript interfaces.
- The
iconprop can accept any validReact.ReactNode. - The
onCloseprop should be a function that takes no arguments and returnsvoid. - Focus should be managed such that when a closable chip is closed, focus can be shifted appropriately (e.g., to the next focusable element or back to the last active chip).
- Avoid hardcoding styles directly within the component's JSX. Use a styling solution like CSS Modules, styled-components, or a dedicated CSS file.
Notes
- Consider using a common pattern for icon components in React (e.g., passing SVG elements directly).
- For styling, think about how to manage hover and focus states. Pseudo-classes in CSS are your friend here.
- For accessibility, ensure the close button has a clear
aria-labeland is keyboard navigable. - Consider adding a
classNameprop to allow for external styling overrides or additional custom classes. - Think about how the
onCloseevent handler will be integrated into your application's state management. The component itself should only be responsible for calling the handler.