Radio
Create consistent cross-browser and cross-device radio buttons with the Chassis Radio component.
Overview
<Radio> replaces the browser's default radio input, for selecting one option from many. It renders the modern, wrapper-based .check-input markup nested inside a single <label> — passing label renders an accessible, fully-clickable control with no extra markup required.
<Radio> is built on React Aria for full keyboard and screen-reader support. Radios have no meaningful standalone state — a radio only makes sense as part of a mutually-exclusive set — so <Radio> must always be rendered inside a <RadioGroup>, which manages selection and arrow-key navigation between options.
Radios
Radios are always rendered inside a <RadioGroup>, which owns selection and gives the group a <fieldset>/<legend> so assistive technology announces the group's purpose alongside each option.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Choose an option" defaultValue="default">
<Radio value="default" label="Default radio" />
<Radio value="checked" label="Checked radio" />
</RadioGroup>
)
}Disabled
Disable a single option by adding disabled to that <Radio>, or disable the whole group by adding disabled to <RadioGroup>.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Choose an option" defaultValue="checked">
<Radio value="default" label="Disabled radio" disabled />
<Radio value="checked" label="Disabled checked radio" disabled />
</RadioGroup>
)
}Stacked
Any number of radios that are immediate siblings are vertically stacked and appropriately spaced by default.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Options" defaultValue="option1">
<Radio value="option1" label="Default radio" />
<Radio value="option2" label="Second default radio" />
<Radio value="option3" label="Disabled radio" disabled />
</RadioGroup>
)
}Inline
Radio groups have a built-in orientation prop to lay options out on the same horizontal row, which also switches arrow-key navigation from vertical to horizontal.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Options" defaultValue="option1" orientation="horizontal">
<Radio value="option1" label="1" />
<Radio value="option2" label="2" />
<Radio value="option3" label="3 (disabled)" disabled />
</RadioGroup>
)
}Context colors
Radios accept a color prop to color the check indicator with any of the Chassis contextual colors.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Success option" defaultValue="checkSuccess">
<Radio color="success" value="checkSuccess" label="Success radio" />
</RadioGroup>
)
}Without labels
Omitting label still requires an accessible name for assistive technology — pass aria-label (or aria-labelledby) directly to the <Radio> instead.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup aria-label="Radio without a visible label" defaultValue="">
<Radio value="" aria-label="..." />
</RadioGroup>
)
}Toggle buttons
Create button-like radios by using the button prop on <Radio>. These toggle buttons can further be grouped in a button group if needed.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup aria-label="Radio toggle buttons" defaultValue="checked" orientation="horizontal">
<Radio button={{ color: 'secondary' }} value="checked" label="Checked" />
<Radio button={{ color: 'secondary' }} value="radio" label="Radio" />
<Radio button={{ color: 'secondary' }} value="disabled" label="Radio" disabled />
<Radio button={{ color: 'secondary' }} value="radio2" label="Radio" />
</RadioGroup>
)
}Outlined styles
<Radio button> accepts the same style variants as <Button>, including the various outlined styles.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup
aria-label="Outlined radio toggle buttons"
defaultValue="success-outlined"
orientation="horizontal"
>
<Radio
button={{ color: 'success', variant: 'outline' }}
value="success-outlined"
label="Radio"
/>
<Radio
button={{ color: 'danger', variant: 'outline' }}
value="danger-outlined"
label="Radio"
/>
</RadioGroup>
)
}Validation
<RadioGroup> accepts invalid/valid and an errorMessage, rendered below the options and linked via aria-describedby.
import { Radio, RadioGroup } from '@chassis-ui/react'
export const Example = () => {
return (
<RadioGroup label="Select a plan" invalid errorMessage="Please choose a plan to continue.">
<Radio value="basic" label="Basic" />
<Radio value="pro" label="Pro" />
</RadioGroup>
)
}API
Radio
| Prop | Type | Default |
|---|---|---|
button? | ButtonObject | — |
Create button-like radios. Combine with <RadioGroup> to build radio toggle-button groups. | ||
className? | string | — |
| A string of all className you want applied to the component. | ||
color? | ContextColor | — |
Sets the color of the radio indicator to one of Chassis context colors. Ignored when button is set. | ||
id? | string | — |
| The id global attribute defines an identifier (ID) that must be unique in the whole document. | ||
label? | ReactNode | — |
The element represents a caption for a component.
Children are accepted as an alias for this prop — label wins when both are given.
react-aria, which backs this component, calls the same thing children; this package renames
it to label, and honouring both means the shape React developers reach for first still
names the control instead of silently producing an unlabelled one. | ||
size? | "sm" | "lg" | — |
| Size the component sm or lg. | ||
value | string | — |
The value of the radio button, used to identify it within its <RadioGroup>. | ||
RadioGroup
| Prop | Type | Default |
|---|---|---|
children | ReactNode | — |
One or more <Radio> elements. | ||
className? | string | — |
| A string of all className you want applied to the component. | ||
defaultValue? | string | — |
| The selected value, uncontrolled. | ||
description? | ReactNode | — |
| A description for the group, rendered below the options. | ||
disabled? | boolean | — |
| Disables every radio in the group. | ||
errorMessage? | ReactNode | — |
An error message for the group, rendered below the options when invalid is set, and after
a submit the group held back, until it no longer would. | ||
form? | string | — |
The id of the <form> the group belongs to, for a group rendered outside it. Reaches every
radio; a Radio with its own form keeps it. | ||
invalid? | boolean | — |
Set group validation state to invalid. Left unset, the group shows as invalid by itself
from a submit it held back (an empty required one, say) until it no longer would, or its
form is reset. Set it, to false too, and it alone decides. | ||
label? | ReactNode | — |
The group's caption, rendered as a <legend>. | ||
name? | string | — |
| The name for the group, used for native form submission. | ||
onChange? | ((value: string) => void) | — |
| Callback fired when the selected value changes. | ||
orientation? | "horizontal" | "vertical" | — |
| Lay the group's radios out on the same horizontal row instead of stacking them. | ||
required? | boolean | — |
Marks the group as required: aria-required on the group and the native required on its
radios, so a form isn't submitted until one of them is selected. | ||
valid? | boolean | — |
| Set group validation state to valid. | ||
value? | string | — |
| The selected value, controlled. | ||