Checkbox, Radio & Switch
Preview
Checkboxes pick several options, a radio group picks one, and a switch turns a setting on or off.
Example
const CHANNELS = ['Organic search', 'Paid social', 'Email', 'Direct'];
const [channels, setChannels] = useState(['Email', 'Direct']);
const all = channels.length === CHANNELS.length;
<Checkbox
label="All channels"
checked={all}
indeterminate={channels.length > 0 && !all}
onChange={(on) => setChannels(on ? CHANNELS : [])}
/>
{CHANNELS.map((c) => (
<Checkbox
key={c}
label={c}
checked={channels.includes(c)}
onChange={(on) => setChannels(on ? [...channels, c] : channels.filter((x) => x !== c))}
/>
))}
<RadioGroup aria-label="Aggregation" options={['Sum', 'Average', 'Median']} defaultValue="Sum" />
<Switch label="Compare to previous period" defaultChecked showState />
<Switch label="Email me when this report changes" description="Sent at most once a day." size="sm" />Usage
All three are controlled (checked or value with onChange) or uncontrolled (defaultChecked or defaultValue). onChange receives the new boolean or value, not an event.
indeterminate is controlled: the checkbox shows a dash for as long as you pass true. Clear it in onChange, or derive it from state as above.RadioGroup takes options (strings or { value, label, description }), or compose <Radio> children yourself.
Props
Checkbox
PropTypeDefaultDescription
checkedboolean——
defaultCheckedbooleanfalse—
indeterminatebooleanfalseMixed state, e.g. a "select all" when some rows are selected. Shows a dash. Controlled: clear it in
onChange.onChange(checked: boolean) => void——
labelReactNode——
descriptionReactNode—Second line under the label.
Also accepts the props of Omit< InputHTMLAttributes<HTMLInputElement>, 'type' | 'size' | 'onChange' | 'checked' | 'defaultChecked' >, spread onto the root element.
RadioGroup
PropTypeDefaultDescription
options(string | RadioOption)[]—Strings are used as both value and label. Omit to compose
<Radio> children instead.valuestring | null——
defaultValuestring | nullnull—
onChange(value: string) => void——
namestring—Form name shared by the radios. Generated when omitted.
orientation'horizontal' | 'vertical''horizontal'—
disabledboolean——
classNamestring——
styleCSSProperties——
childrenReactNode——
aria-labelstring——
aria-labelledbystring——
RadioOption
PropTypeDefaultDescription
valuerequiredstring——
labelrequiredReactNode——
descriptionReactNode——
disabledboolean——
Switch
PropTypeDefaultDescription
checkedboolean——
defaultCheckedbooleanfalse—
onChange(checked: boolean) => void——
labelReactNode——
descriptionReactNode—Second line under the label.
size'sm' | 'md''md'sm: 28 × 16 track · md: 32 × 18.
showStatebooleanfalseShows "On" / "Off" in mono after the label.
Also accepts the props of Omit< InputHTMLAttributes<HTMLInputElement>, 'type' | 'size' | 'onChange' | 'checked' | 'defaultChecked' | 'role' >, spread onto the root element.
Accessibility
- Native inputs with their labels attached; Space toggles a checkbox or switch.
- The indeterminate checkbox reports the mixed state to assistive technology.
- RadioGroup is a native radio group: arrow keys move and select. Name it with
aria-labeloraria-labelledby. - Switch is an input with the switch role.
Report an issueBuilt Oct 21, 2026