Skip to main content

Radio Group

Single-selection radio buttons with roving focus, typeahead, vim-style navigation, and form integration.

import * as RadioGroup from '@gentleduck/primitives/radio-group'
import * as RadioGroup from '@gentleduck/primitives/radio-group'

Anatomy

<RadioGroup.Root>
  <RadioGroup.Item value="comfortable">
    <RadioGroup.Indicator />
  </RadioGroup.Item>
</RadioGroup.Root>
<RadioGroup.Root>
  <RadioGroup.Item value="comfortable">
    <RadioGroup.Indicator />
  </RadioGroup.Item>
</RadioGroup.Root>

Example

import * as RadioGroup from '@gentleduck/primitives/radio-group'
 
function DensityPicker() {
  return (
    <RadioGroup.Root defaultValue="comfortable" name="density" className="grid gap-2">
      <RadioGroup.Item value="compact" textValue="Compact" aria-label="Compact density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
      <RadioGroup.Item value="comfortable" textValue="Comfortable" aria-label="Comfortable density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
      <RadioGroup.Item value="spacious" textValue="Spacious" aria-label="Spacious density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
    </RadioGroup.Root>
  )
}
import * as RadioGroup from '@gentleduck/primitives/radio-group'
 
function DensityPicker() {
  return (
    <RadioGroup.Root defaultValue="comfortable" name="density" className="grid gap-2">
      <RadioGroup.Item value="compact" textValue="Compact" aria-label="Compact density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
      <RadioGroup.Item value="comfortable" textValue="Comfortable" aria-label="Comfortable density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
      <RadioGroup.Item value="spacious" textValue="Spacious" aria-label="Spacious density">
        <RadioGroup.Indicator />
      </RadioGroup.Item>
    </RadioGroup.Root>
  )
}

API

RadioGroup.Root

Container for a single-selection radio set. Uses roving focus and form-compatible hidden radio inputs.

PropTypeDefaultDescription
valuestring--Controlled selected value
defaultValuestring--Initial selected value (uncontrolled)
onValueChange(value: string) => void--Called when selected value changes
disabledbooleanfalseDisables all items in the group
requiredbooleanfalseMarks the group required for form validation
namestring--Name used for hidden native radio inputs
dir'ltr' | 'rtl'--Text direction. Resolved with useDirection (dir prop -> DirectionProvider -> 'ltr').
orientation'horizontal' | 'vertical'--Limits arrow-key navigation axis
loopbooleantrueWraps focus from end to start (and reverse)
...propsReact.ComponentPropsWithoutRef<'div'>--Additional props for the radiogroup container

RadioGroup.Item

A single radio control. Renders a button with role="radio" and associated state data attributes.

PropTypeDefaultDescription
valuestring(required)Unique value for the item
textValuestring--Optional text override used for typeahead matching
disabledbooleanfalseDisables this item
...propsReact.ComponentPropsWithoutRef<'button'>--Additional props for the radio button element

RadioGroup.Indicator

Indicator content that mounts when the parent item is checked.

PropTypeDefaultDescription
forceMounttrue--Force indicator to stay mounted for animation control
...propsReact.ComponentPropsWithoutRef<'span'>--Additional props for the indicator element

Keyboard interactions

KeyAction
ArrowUp / ArrowLeftMove focus to previous item and select it
ArrowDown / ArrowRightMove focus to next item and select it
Home / PageUpMove to first item and select it
End / PageDownMove to last item and select it
a-zTypeahead jump to matching item and select it
g gJump to first item and select it
Shift+g (G)Jump to last item and select it
SpaceSelect focused item