RadioGroup
StableOne choice among a few visible, mutually exclusive options. Arrow keys move the selection; the group has a legend and optional per-option descriptions.
When to use
Use it for
- Two to about six exclusive options that benefit from being compared side by side.
- Options that need a description to choose well.
- horizontal only for two or three short options, like Light, Dark, System.
Not for
- More than about six options, or options users know by name: use Select.
- A single on or off: use Switch or Checkbox.
- Switching views of content: use Tabs.
Do and don't
Every example is rendered with the real component, so it always matches what ships.
Preselect the safest or most common option
A default saves a decision; pick the one most teams want.
A single radio button
One radio cannot be unselected. Use a Checkbox.
Accessibility
- Base UI RadioGroup: role radiogroup named by the legend; one tab stop, arrow keys move and select.
- Each radio is labelled by its text (aria-labelledby) and described by its description.
- The group error is linked with aria-describedby and sets aria-invalid; it shows an icon and text.
- Selected uses the ink fill with a light dot; the unselected edge is color.border.strong (3:1).
Anatomy and tokens
Read from packages/react/src/components/RadioGroup/RadioGroup.module.css at build time. Every value is a token: open one to see its
alias chain in both themes.
- Fieldset container
.fieldset - Legend (group label)
.legend - Fieldset container, disabled
.fieldset:disabled .legend - hiddenLegend
.hiddenLegend - required
.required - description
.description, .error - description
.description - Error message
.error - errorIcon
.errorIcon - Radio list
.group - horizontal
.horizontal - Option row (click target)
.item - Radio circle
.radio - Option row (click target), hover
@media (hover: hover) .item:hover .radio:not([data-disabled], [data-checked]) - Option row (click target), hover
@media (hover: hover) .item:hover .radio[data-checked]:not([data-disabled]) - Radio circle, focus
.radio:focus-visible - Radio circle
.radio[data-checked] - Fieldset container
.fieldset[data-invalid] .radio:not([data-checked]) - Selected dot
.dot - text
.text - Option description
.itemDescription - Option row (click target)
.item:has([data-disabled]) - Option row (click target)
.item:has([data-disabled]) .itemDescription - Radio circle
.radio[data-disabled] - Selected dot
.dot[data-disabled]
Props
Parsed from the TypeScript types in packages/react/src/components/RadioGroup/RadioGroup.tsx, so this table cannot drift from the
code.
| Prop | Type | Default | Description |
|---|---|---|---|
label required | ReactNode | none | Group label, rendered as the fieldset legend. Ask the question the options answer. |
children required | ReactNode | none | Radio items. |
description | ReactNode | none | Help under the legend. |
error | ReactNode | none | Error message for the group. Marks it invalid and is linked with aria-describedby. |
value | string | none | No description in the code yet. |
defaultValue | string | none | No description in the code yet. |
onValueChange | (value: string) => void | none | No description in the code yet. |
orientation | 'vertical' | 'horizontal' | 'vertical' | Default `vertical`. Use `horizontal` only for two or three short options. |
name | string | none | No description in the code yet. |
disabled | boolean | none | No description in the code yet. |
readOnly | boolean | none | No description in the code yet. |
required | boolean | none | No description in the code yet. |
hideLabel | boolean | false | Visually hide the legend (it stays the accessible name). |
className | string | none | No description in the code yet. |
Playground
Change the props and see the real RadioGroup update. Controls are generated from the TypeScript props; nothing here changes the system.
<RadioGroup defaultValue="squash" label="Merge strategy" />Workbench
For contributors: every state with the accessibility panel, in the component workbench (Storybook). The stories double as visual test fixtures; the guidance on this page is the user documentation (open RadioGroup in Storybook) .
Embed Storybook stories here (4)
Loads from https://bridge-storybook.floriangouloubi.com (set STORYBOOK_URL at build time). If Storybook is not running, the frames stay
empty.
Default
Horizontal
Invalid
AllStates
Changelog
- New
Forms: Field (label, description, error wired by Base UI Field) and Input rebuilt on it (prefix, suffix, sizes; label, hint and error props kept). New Textarea (autosize, character count), Select (groups, descriptions), Combobox (filtering, async loading and empty states, multiple with chips), Checkbox (indeterminate, parent), CheckboxGroup, RadioGroup, Switch, Slider (single and range), NumberField (steppers, units) and Form (server errors with a focusable error summary, FormActions footer).
Unreleased (current version 0.1.0, no release tagged yet) , Oct 17, 2026