Skip to Content
ComponentsRadioGroup

RadioGroup

A group of mutually-exclusive options with roving tabindex.

Anatomy

import { RadioGroup } from "@spacing-ui/core"; <RadioGroup defaultValue="medium" onValueChange={(v) => console.log(v)}> <RadioGroup.Item value="small">Small</RadioGroup.Item> <RadioGroup.Item value="medium">Medium</RadioGroup.Item> <RadioGroup.Item value="large">Large</RadioGroup.Item> </RadioGroup>;

API

RadioGroup (Root)

PropTypeDefaultDescription
value / defaultValuestring
onValueChange(value: string) => void
namestringauto-generatedNative form name
disabledbooleanfalse
orientation"horizontal" | "vertical""vertical"

Accessibility

  • role="radiogroup", items have role="radio"
  • Roving tabindex: only the checked item (or first item) is in the tab order
  • Keyboard: ArrowDown/Up (vertical) or ArrowRight/Left (horizontal)

Examples

Horizontal orientation

<RadioGroup defaultValue="left" orientation="horizontal"> <RadioGroup.Item value="left">Left</RadioGroup.Item> <RadioGroup.Item value="center">Center</RadioGroup.Item> <RadioGroup.Item value="right">Right</RadioGroup.Item> </RadioGroup>

Arrow keys follow orientation: Right/Left for horizontal, Up/Down for vertical.

Native form submission

<form action="/prefs" method="post"> <RadioGroup name="theme" defaultValue="system"> <RadioGroup.Item value="light">Light</RadioGroup.Item> <RadioGroup.Item value="dark">Dark</RadioGroup.Item> <RadioGroup.Item value="system">Match system</RadioGroup.Item> </RadioGroup> </form>

Renders hidden native inputs so FormData picks up the selected value.

Live demo

Orientation & wrapping

The orientation prop only affects arrow-key handling — it doesn’t lay items out. Use your own CSS (flex row / column, grid) to visually match the arrow-key behavior.

Testing

const radios = screen.getAllByRole("radio"); await userEvent.click(radios[2]); expect(radios[2]).toBeChecked();
Last updated on