Hone logo
Hone
Problems

React Radio Button Group Component

This challenge asks you to build a reusable React component that renders a group of radio buttons. Radio buttons are essential for allowing users to select one option from a predefined set, and a well-designed component simplifies their integration into various forms and interfaces. This exercise will reinforce your understanding of React state management, event handling, and component composition.

Problem Description

You need to create a RadioGroup component in React using TypeScript. This component should accept an array of options, each with a value and a label. The component should render a set of radio buttons, one for each option. The user should be able to select only one radio button at a time. The component should maintain an internal state to track the currently selected value and provide a way for the parent component to access this selected value.

Key Requirements:

  • Props: The component should accept the following props:
    • options: An array of objects, where each object has a value (string or number) and a label (string). Example: [{ value: 'option1', label: 'Option 1' }, { value: 'option2', label: 'Option 2' }]
    • value: (Optional) The initially selected value. If not provided, no radio button should be initially selected.
    • onChange: A function that will be called when the selected radio button changes. This function should receive the new selected value as an argument.
  • Rendering: The component should render a <div> containing a set of <input type="radio"> elements, one for each option. Each radio button should be associated with its corresponding option's value.
  • State Management: The component should manage its own internal state to track the currently selected value.
  • Event Handling: The component should handle the onChange event for each radio button and update its internal state accordingly. It should also call the onChange prop function with the new selected value.
  • Accessibility: Ensure the radio buttons are accessible (e.g., proper labels, ARIA attributes if needed).

Expected Behavior:

  • When the component mounts, if an initial value is provided, the corresponding radio button should be selected.
  • When a user clicks on a radio button, the component should update its internal state to reflect the new selection.
  • The onChange prop function should be called with the new selected value whenever the user changes the selection.
  • Only one radio button should be selectable at a time.

Edge Cases to Consider:

  • Empty options array: The component should render nothing or a suitable message.
  • Invalid value prop: Handle cases where the provided value doesn't match any of the options.
  • onChange prop is not a function: Gracefully handle this situation (e.g., log a warning).

Examples

Example 1:

Input:
options: [{ value: 'a', label: 'Option A' }, { value: 'b', label: 'Option B' }]
value: 'a'
onChange: (selectedValue) => console.log('Selected:', selectedValue)

Output:
<div role="group" aria-label="Radio Group">
  <input type="radio" id="a" name="group" value="a" checked onChange={() => onChange('a')} />
  <label htmlFor="a">Option A</label>
  <input type="radio" id="b" name="group" value="b" onChange={() => onChange('b')} />
  <label htmlFor="b">Option B</label>
</div>

Explanation: The component renders two radio buttons, 'A' is initially selected because value is 'a'. Clicking 'B' will call onChange with 'b'.

Example 2:

Input:
options: [{ value: 'cat', label: 'Cat' }, { value: 'dog', label: 'Dog' }, { value: 'bird', label: 'Bird' }]
onChange: (selectedValue) => alert(selectedValue)

Output:
<div role="group" aria-label="Radio Group">
  <input type="radio" id="cat" name="group" value="cat" onChange={() => onChange('cat')} />
  <label htmlFor="cat">Cat</label>
  <input type="radio" id="dog" name="group" value="dog" onChange={() => onChange('dog')} />
  <label htmlFor="dog">Dog</label>
  <input type="radio" id="bird" name="group" value="bird" onChange={() => onChange('bird')} />
  <label htmlFor="bird">Bird</label>
</div>

Explanation: All radio buttons are initially unselected. Clicking any button will trigger the alert with the selected value.

Example 3:

Input:
options: []
value: 'someValue'
onChange: (selectedValue) => console.log(selectedValue)

Output:
(Nothing is rendered)

Explanation: Since the options array is empty, the component renders nothing. The value prop is ignored.

Constraints

  • The component must be written in TypeScript.
  • The component should be reusable and accept the options, value, and onChange props.
  • The component should handle the edge case of an empty options array gracefully.
  • The component should be accessible.
  • The component should be reasonably performant (no unnecessary re-renders).

Notes

  • Consider using React's useState hook for state management.
  • Pay attention to accessibility best practices when rendering radio buttons and labels. Use htmlFor attributes to associate labels with their corresponding radio buttons.
  • The name attribute on the radio buttons should be the same for all buttons in the group.
  • Think about how to handle the case where the provided value prop doesn't match any of the options in the options array. You might choose to ignore it or log a warning.
Loading editor...
typescript