Radios

Radios collect exactly one choice from a set of visible options, as plain labeled circles with optional hints, built on React Aria’s RadioGroup.

Demo

Change the props and copy the result. The component select switches between the full RadioGroup and the bare RadioButtonBase, whose state controls are all real props.

Component
size
import { RadioGroup } from "@/components/base/radio-buttons/radio-buttons"; <RadioGroup size="md" aria-label="Remember settings" />

The group’s options are fixed

A RadioGroup needs RadioButton children, which the playground’s copyable snippet cannot carry, so the snippet covers the group element only and the two options stay fixed. Paste a full example from the Code tab when starting from scratch.

The family

Two layers from one module: the primitive group and button most forms use, and the bare visual circle they are built around. The card-style groups over the same semantics live on the Radio groups page.

The components in this family, with their descriptions and import paths
ComponentDescriptionImport from
RadioGroupThe group container: owns the selection, the form value, and the size of every button inside.@/​components/​base/​radio-buttons/​radio-buttons
RadioButtonOne option: the circle with an optional label and hint, built on React Aria’s Radio. Only works inside a RadioGroup.@/​components/​base/​radio-buttons/​radio-buttons
RadioButtonBaseThe bare visual circle. Renders two divs and nothing interactive; compose it inside your own Radio.@/​components/​base/​radio-buttons/​radio-buttons

The primitive

Both sizes with every text form, all live. The circle measures 16px at sm and 20px at md, and the labels step with it, text-sm to text-md. A radio without a visible label still needs an aria-label; the bare cells below carry one.

sm
label
label and hint
no visible label
md
label
label and hint
no visible label

The whole row selects

Label and hint live inside one label element with the hidden radio input, and clicking any of them selects the option; the hint is not click-inert, measured with a real browser. A group stacks its options vertically with nothing in the kit for a horizontal row.

States

Every treatment below is painted by the kit itself: RadioButtonBase takes its states as plain props, so nothing in this grid is a hand-copied approximation.

sm
rest
selected
focus-visible
focus-visible, selected
disabled
disabled, selected
md
rest
selected
focus-visible
focus-visible, selected
disabled
disabled, selected

No hover, by design

The kit styles no hover state anywhere in this family, and the Figma sheet agrees: its Hover variants are pixel-identical to Default, measured in this page’s parity audit. Focus, unlike on most families, can be forced honestly here: RadioButtonBase paints it from the isFocusVisible prop in the grid above.

Survives forced colors since 2026-08-22

Every part of this circle was a box-shadow ring or a background-color, and forced colors mode drops the first and flattens the second to Canvas. Measured 2026-08-22 in Chromium’s forced-colors emulation against a production build, on the breadcrumbs account menu, which renders this circle as its selected marker: the circle, the selected fill and the dot all vanished, and selected and unselected rendered alike. The kit edit gives the circle a real border there, GrayText when disabled, and paints the selected dot in CanvasText, so rest, selected and disabled stay distinct in every cell above; that is stated from the source and the forced-colors rules, not re-measured on this grid. Nothing changes outside forced colors, and nothing moves inside it: the box is border-box at an explicit size.