Skip to main content

RadioGroup

  • Component overview: Radio button group for single selection among mutually exclusive options.
  • Interaction: The current spec covers the unchecked, checked, disabled, and hover main matrix.
  • Implementation note: RadioGroup retains the mutually exclusive selection structure; the design layer owns the border, fill, and inner circle visuals.
  • Figma spec

Basic Usage

Pass label to make the entire row (control + text) clickable.

Result
Loading...
Live Editor
render(
  <RadioGroup defaultValue="option1" aria-label="Favorite fruit">
    <RadioGroupItem value="option1" label="Apple" />
    <RadioGroupItem value="option2" label="Banana" />
    <RadioGroupItem value="option3" label="Cherry" />
  </RadioGroup>,
)

Disabled State

Result
Loading...
Live Editor
render(
  <RadioGroup defaultValue="option1" disabled aria-label="Disabled group">
    <RadioGroupItem value="option1" label="Selected (disabled)" />
    <RadioGroupItem value="option2" label="Unselected (disabled)" />
  </RadioGroup>,
)

Hover and Main Matrix

Result
Loading...
Live Editor
render(
  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 24, alignItems: 'center' }}>
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
      <RadioGroup aria-label="Unchecked default">
        <RadioGroupItem value="default-unchecked" aria-label="Unchecked default" />
      </RadioGroup>
      <span style={{ fontSize: 12, color: '#999' }}>Unchecked Default</span>
    </div>
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
      <RadioGroup aria-label="Unchecked hover">
        <RadioGroupItem value="hover-unchecked" className="border-[var(--Labels-Primary)]" aria-label="Unchecked hover" />
      </RadioGroup>
      <span style={{ fontSize: 12, color: '#999' }}>Unchecked Hover</span>
    </div>
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
      <RadioGroup defaultValue="default-checked" aria-label="Checked default">
        <RadioGroupItem value="default-checked" aria-label="Checked default" />
      </RadioGroup>
      <span style={{ fontSize: 12, color: '#999' }}>Checked Default</span>
    </div>
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
      <RadioGroup defaultValue="disabled-checked" disabled aria-label="Checked disabled">
        <RadioGroupItem value="disabled-checked" aria-label="Checked disabled" />
      </RadioGroup>
      <span style={{ fontSize: 12, color: '#999' }}>Checked Disabled</span>
    </div>
  </div>,
)

Namespace Usage

Result
Loading...
Live Editor
render(
  <Controls.RadioGroup defaultValue="a" aria-label="Namespace radio">
    <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
      <Controls.RadioGroupItem value="a" aria-label="A" />
      <span style={{ fontSize: 14 }}>Controls.RadioGroupItem</span>
    </div>
  </Controls.RadioGroup>,
)

RadioGroup Props

PropTypeDefaultDescription
valuestringControlled selected value
defaultValuestringDefault selected value (uncontrolled)
disabledbooleanfalseDisables the entire group
onValueChange(value: string) => voidSelected value change callback
orientation'horizontal' | 'vertical''vertical'Layout direction
classNamestringCustom style class
aria-labelstringAccessibility label

RadioGroupItem Props

PropTypeDefaultDescription
valuestringOption value (required)
labelstringLabel text; when set, the entire row (control + text) is clickable
disabledbooleanfalseDisables this item
labelClassNamestringCustom style class for the label row
classNamestringCustom style class
aria-labelstringAccessibility label