Headless / Selection

RadioGroup

RadioGroup captures a one-of-many choice. It synchronises a shared name and the current value across its Radio children — each a real native radio input.

Loading playground…
Updated 3 days agoEdit on GitHubWeb & native

What it is

A two-part component. RadioGroup is a role="radiogroup" container that holds the selected value and a shared form name. Radio is a <input type="radio"> that reads both from context — it is checked when its value matches the group's, and selecting it updates the group.

The inputs are real, so the group posts with a <form> and resets natively. Radio must be rendered inside a RadioGroup; on its own it has no context to read.

Install

example.tsx
yarn add @usemotif/headless
example.tsx
import { RadioGroup, Radio } from '@usemotif/headless';

Anatomy

example.tsx
<RadioGroup aria-label="Shipping speed" defaultValue="standard">
<label><Radio value="standard" /> Standard</label>
<label><Radio value="express" /> Express</label>
<label><Radio value="overnight" /> Overnight</label>
</RadioGroup>

API

RadioGroup

RadioGroup

stable
function RadioGroup(props: RadioGroupProps): JSX.Element
valuestring

Controlled selected value. Pass alongside `onValueChange`.

defaultValuestring

Initially selected value for the uncontrolled mode.

onValueChange(next: string) => void

Called when the selection changes.

namestring

The form `name` shared by every Radio. Generated when omitted.

aria-label / aria-labelledbystring

Names the group. One is required so the radiogroup announces as a single composite control.

childrenReactNode

The Radio inputs, usually each inside a label.

Radio

Radio

stable
const Radio: ForwardRefExoticComponent<RadioProps & RefAttributes<HTMLInputElement>>
valuestringrequired

This option's value. The Radio is checked when it matches the group's value.

…InputHTMLAttributesOmit<InputHTMLAttributes, "type" | "value">

Every standard input attribute except `type` and `value`. `name` and `checked` are managed by the group.

Accessibility

RadioGroup renders role="radiogroup" and needs a name — aria-label or aria-labelledby — so assistive technology announces the group as one control with a question, not a loose run of radios. Each Radio is a native radio input, so the arrow keys move between options and Space selects, all from the platform. Give each Radio a visible label via a wrapping <label>.

Examples

A controlled radio group:

example.tsx
<RadioGroup
aria-label="Notification frequency"
value={frequency}
onValueChange={setFrequency}
>
<label><Radio value="all" /> Every update</label>
<label><Radio value="daily" /> A daily digest</label>
<label><Radio value="none" /> Nothing</label>
</RadioGroup>