Radio Group

PreviousNext

A group of radio buttons for single-choice selection with keyboard navigation and accessibility support

'use client';

import { FormControl } from '@/ui/forms/FormControl';
import { RadioGroup } from '@/ui/forms/radios/RadioGroup';
import { Radio } from '@/ui/forms/radios/Radio';
import { useState } from 'react';

export function RadioGroupDemo() {
  const [value, setValue] = useState('option1');

  return (
    <FormControl label="Choose an option" id="demo-radio-group">
      <RadioGroup
        value={value}
        onChange={(_, newValue) => setValue(newValue)}
        name="demo-radio-group"
        aria-labelledby="demo-radio-group"
      >
        <Radio value="option1">Option 1</Radio>
        <Radio value="option2">Option 2</Radio>
        <Radio value="option3">Option 3</Radio>
      </RadioGroup>
    </FormControl>
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/radio-group.json

Usage

'use client';
 
import { FormControl } from '@/docs/lib/ui/forms/form-control';
import { RadioGroup } from '@/docs/lib/ui/forms/radios/radio-group';
import { Radio } from '@/docs/lib/ui/forms/radios/radio';
import { useState } from 'react';
 
export function Component() {
  const [value, setValue] = useState('option1');
 
  return (
    <FormControl label="Choose an option" id="radio-example">
      <RadioGroup
        value={value}
        onChange={(name, newValue) => {
          console.log(`${name} changed to:`, newValue);
          setValue(newValue);
        }}
        name="radio-group"
        aria-labelledby="radio-example"
      >
        <Radio value="option1">Option 1</Radio>
        <Radio value="option2">Option 2</Radio>
        <Radio value="option3">Option 3</Radio>
      </RadioGroup>
    </FormControl>
  );
}

API Reference

RadioGroup

PropTypeDefaultDescription
childrenReactNodeundefinedRadio or Button components to be grouped together
idstringautoUnique identifier for the radio group. Auto-generated if not provided
namestringidName attribute for the radio group, used in form submissions. Defaults to the id value
valueValueundefinedCurrently selected value. Can be any type (string, number, etc.)
defaultValueValueundefinedDefault selected value for uncontrolled component usage
onChange(name: string, value: Value) => voidundefinedCallback function called when the selected value changes. Receives the name and new value
disabledbooleanfalseIf true, disables all radio buttons in the group
readOnlybooleanfalseIf true, makes the radio group read-only (no changes allowed)
tabIndexnumber0Tab index for keyboard navigation. First or selected radio gets this value, others get -1
classNamestringundefinedAdditional CSS classes to apply to the radio group container
...restOmit<HTMLAttributes<HTMLDivElement>, "onChange">-All standard HTML div attributes except onChange

Notes

  • FormControl Integration: RadioGroup should typically be wrapped in a FormControl component for labels, descriptions, validation status, and error messages. Pass label, description, validationStatus, and errorMessage props to FormControl, not RadioGroup
  • Keyboard Navigation: Use Arrow keys (Up/Down/Left/Right) to navigate between radio options. Press Space or Enter to select the focused option
  • Accessibility: Implements proper ARIA attributes including role="radiogroup", role="radio", aria-checked, and roving tabindex for keyboard navigation. Use aria-labelledby to connect RadioGroup to FormControl's label
  • Generic Value Type: Supports any value type (string, number, object, etc.) through TypeScript generics
  • Automatic State Management: Uses the useValue hook internally to manage state, supporting both controlled and uncontrolled usage
  • Button Support: Can accept Button components as children for a button-style radio group with automatic styling (selected buttons get black color, unselected get white)
  • Radio Support: Can accept Radio components as children for traditional radio button appearance
  • Mixed Children: Supports non-Radio/Button children (like text or spans) which are rendered as-is without modification
  • Roving Tabindex: Implements the roving tabindex pattern - only one radio button is tabbable at a time, improving keyboard navigation
  • Client Component: This component uses hooks and event handlers, so it must be used in a client component (use "use client" directive)
  • Gap Spacing: Radio options are spaced with a 12px gap by default (can be overridden with className)
  • Data Attributes: Uses data-value attribute on Button children for keyboard navigation and selection logic