Skip to main contentSkip to docs navigation

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.

Choose an option
JSX
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>.

Choose an option
JSX
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.

Options
JSX
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.

Options
JSX
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.

Success option
JSX
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.

JSX
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.

JSX
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.

JSX
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.

Select a plan
Please choose a plan to continue.
JSX
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

PropTypeDefault
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.
valuestring—
The value of the radio button, used to identify it within its <RadioGroup>.

RadioGroup

PropTypeDefault
childrenReactNode—
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.