Radio
MD3 radio button, built on a native <input type="radio">. Wrap radios in a
RadioGroup to share a name, manage the selected value, and expose a
role="radiogroup".
RadioGroup
RadioGroup hands a shared name to every Radio inside it (at any depth)
and tracks the selection. Use defaultValue for an uncontrolled group.
<RadioGroup aria-label="Notification frequency" defaultValue="daily">
<label>
<Radio value="realtime" /> Real time
</label>
<label>
<Radio value="daily" /> Daily digest
</label>
</RadioGroup>
Controlled
Pass value and onChange. onChange receives the native event and the
newly selected value (MUI-style (event, value)).
Selected: medium
const [value, setValue] = useState('medium')
<RadioGroup aria-label="Size" value={value} onChange={(event, next) => setValue(next)}>
<label><Radio value="small" /> Small</label>
<label><Radio value="medium" /> Medium</label>
<label><Radio value="large" /> Large</label>
</RadioGroup>
Standalone radios
Without a group, radios that share a name behave like native radios: the
browser keeps them mutually exclusive. A Radio's own onChange fires with
(event, value) when that radio becomes selected.
<Radio name="plan" value="a" defaultChecked aria-label="Option A" />
<Radio name="plan" value="b" aria-label="Option B" />
Disabled
Disable a single radio, or every radio at once with <RadioGroup disabled>.
<RadioGroup aria-label="Plan" defaultValue="free" disabled>
…
</RadioGroup>
Accessibility
- Each radio is a native
<input type="radio">: Tab moves into the group (to the selected radio), arrow keys move the selection within it, and Space selects — all native behavior. - Give every radio an accessible name: wrap it in a
<label>with visible text, or passaria-label. - Name the group with
aria-labeloraria-labelledbyonRadioGroup. - The touch target is 48dp.
refpoints at the root element;inputRefreaches the native input.
Props
Radio
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled checked state. |
defaultChecked | boolean | — | Uncontrolled initial checked state (native input behavior — the browser manages group exclusivity for radios sharing a `name`). |
inputRef | Ref<HTMLInputElement> | — | Ref to the native `<input>` element (the forwarded `ref` points at the root). |
onChange | ((event: ChangeEvent<HTMLInputElement, Element>, value: string) => void) | — | Fires with the native event and this radio's `value` (as a string — the same value a wrapping `RadioGroup` reports) when the radio is selected. |
RadioGroup
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | `Radio` elements (any depth). |
defaultValue | string | — | Uncontrolled initial selected value. |
disabled | boolean | false | Disable every radio in the group. |
name | string | — | Shared input name for the group. Auto-generated when omitted. |
onChange | ((event: ChangeEvent<HTMLInputElement, Element>, value: string) => void) | — | Fires with the native event and the newly selected value. |
value | string | — | Controlled selected value. |