Radio group

Picks exactly one option from a short list where all are visible.

Examples

Options with what they mean

Plan

A choice you must make

Reply language for the Billing queue

 

Content

  • labeldefault

  • label and description

  • radio only

States

  • rest

  • hover

  • focus-visible

  • chosen

  • disabled

  • invalid

Usage

When to use it
Use
The person picks exactly one of 2 to 6 options that are worth seeing together.
Use
Options differ in what they cost or do and each needs a line of description.
Not for
More than 6 options. Use Select.
Not for
Any number of the options may apply. Use Checkbox.
Not for
Switching between views of the same data. Use Segmented control.

Rules

6 rules
Must
Name the group with aria-labelledby pointing at its visible question. Because the group is a radiogroup with no name, so a screen reader announces the options without the question.
Should
Pass defaultValue when one option is right for most people; leave it empty only when a wrong default costs money or data.
Must
Put the difference between options in description, not in a tooltip or a link. Because description is tied by aria-describedby and read while arrowing, while a tooltip never opens on touch.
Should
Use the same grammatical form and length for every option label, 1 to 3 words.
Never
Build plan cards with a radio in the corner. Use RadioGroupOption rows with descriptions. Because only the 16px circle is the target and the card text is not read with the radio, so the card looks clickable but is not.
Should
Switch to Select past 6 options.

Accessibility

5 checks
The group is role="radiogroup", named by aria-labelledby, with one tab stop.
Tab focuses the chosen option or the first; arrows move focus and the choice to the next enabled option, wrapping and following visual order in RTL.
Space chooses a clear option.
The description is read once through aria-describedby; the whole row is the target.
A bare RadioGroupItem needs aria-label or a wrapping label.

Edge cases

8 edge cases
Long label and description
Both wrap; the circle stays aligned to the first line.
Right to left
The circle sits at the start (right).
Required and invalid
Rings every circle; the error sits under the group, only after a submit.
On the inverse surface
Ink and paper flip.
One option
Cannot be cleared again; use a Checkbox.
Zero options
An empty group the keyboard skips.
Held arrow key
Each repeat moves the choice one option, wrapping.
Inside a form
Submits through name.

API

7 props
RadioGroup value, defaultValue
unknown
RadioGroup onValueChange
(value, details) => void
RadioGroup aria-invalid
boolean default false
RadioGroup disabled, readOnly, required, name
Base UI
RadioGroupOption label
ReactNode default required
RadioGroupOption description
ReactNode
RadioGroupOption, RadioGroupItem value, disabled
Base UI Radio

Tokens

13 tokens
--surface-page
var(--paper)
--border-control
oklch(var(--ink-c) / 0.50)
--fail-line
oklch(60% 0.236 26)
--radius-full
999px
--ink
oklch(var(--ink-c))
--paper
oklch(var(--paper-c))
--surface-pressed
oklch(var(--ink-c) / 0.08)
--text-disabled
oklch(var(--ink-c) / 0.40)
--type-label
400 14px/16px var(--font-sans)
--type-body-sm
380 13px/18px var(--font-sans)
--text-1
var(--ink)
--text-2
oklch(var(--ink-c) / 0.80)
--ease-step
cubic-bezier(0.2, 0, 0, 1)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.