Radio Group

One choice from a visible, labeled set of options.

Preview

Use Radio Group when exactly one option can be selected. Keep all options visible and give the group a shared name. Try the labels or arrow keys.

Digest frequency

Choose one schedule. Arrow keys move and select within the group.

One summary each morning.

A digest every Monday.

Do not send a digest.

Selected: weekly. Local preview only.

Installation

pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/radio-group.json

Installs Radio Group and its Radix primitive, preserving your theme. Field, Label, and Button are separate optional items. The dot is drawn with CSS, so no icon library is required. See the registry guide for local endpoints and updates.

Usage

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Field, FieldLabel, FieldSet, FieldLegend } from '@/components/ui/field';

<FieldSet>
  <FieldLegend id="digest-label">Digest frequency</FieldLegend>
  <RadioGroup name="digest" defaultValue="weekly" aria-labelledby="digest-label">
    <Field orientation="horizontal" className="gap-2">
      <RadioGroupItem id="daily" value="daily" />
      <FieldLabel htmlFor="daily">Daily</FieldLabel>
    </Field>
    <Field orientation="horizontal" className="gap-2">
      <RadioGroupItem id="weekly" value="weekly" />
      <FieldLabel htmlFor="weekly">Weekly</FieldLabel>
    </Field>
  </RadioGroup>
</FieldSet>

Each item needs a unique value within the group and a labeled ID. Use FieldContent to stack a label and caption-sized description. The group has a 12px option gap; horizontal control-to-label spacing is 8px. Marks are 16px circles with an 8px selected dot. There is no shadow.

Use the group's value and onValueChange for controlled selection; do not control individual items with checked. Selection cannot be cleared by clicking the selected radio again. Offer an explicit “None” option when that is a valid choice.

Composition

Use a fieldset to describe the choice, a RadioGroup to own selection, and a labeled Field for each option:

FieldSet
├── FieldLegend
└── RadioGroup
    └── Field (repeat for each option)
        ├── RadioGroupItem
        └── FieldLabel

Connect RadioGroup's aria-labelledby to the legend's id. Match each FieldLabel's htmlFor to its RadioGroupItem's id; each item also needs a unique value. When an option has supporting text, wrap FieldLabel and FieldDescription in FieldContent, as in the preview. Put shared selection and form props on RadioGroup.

Interaction states

Each specimen below is an independent one-item group for comparing appearance. Use a complete set of options in actual forms. Hover and focus are pinned; disabled items are skipped during navigation.

The selected border and dot use the focus-indicator color, falling back to primary when that token is absent. This keeps the small selection mark bright in dark mode. Invalid item borders and focus outlines use destructive; labels stay neutral.

Required group and form values

Submit without a selection, choose an option, then submit again. Reset clears the controlled selection. This demo validates locally and saves nothing.

Digest frequency (required)

Choose one schedule. Arrow keys move and select within the group.

One summary each morning.

A digest every Monday.

Do not send a digest.

Set required and name on RadioGroup. A selected enabled item contributes the group's name and its value inside a form. An unselected or disabled item contributes no value. For custom validation, mark the group and affected items with aria-invalid, associate an error with the group, and focus its first enabled item when no selection exists.

Keyboard and accessibility

  • Tab enters the group at the selected item, or the first enabled item when no value is selected. Tab again leaves the group.
  • Arrow keys move focus and select an enabled option. Navigation wraps by default (loop). Space selects a focused item.
  • Label the group with aria-labelledby pointing to its visible legend, and label each item separately.
  • Use orientation="horizontal" for a horizontal layout and pass dir="rtl" for a right-to-left group when appropriate.
  • disabled on RadioGroup disables all items; an individual item can also be disabled. Keep corresponding labels in the same disabled visual state.
  • Keep label targets generous for touch and preserve the distinct dot so color is not the only selection cue.
<RadioGroup orientation="horizontal" className="flex flex-wrap gap-4"
  aria-label="Alignment" defaultValue="start">
  {/* Labeled RadioGroupItem controls */}
</RadioGroup>

API

Part / propDefaultPurpose
Group value / defaultValueUnselectedControlled or initial selected value
Group onValueChange—Receives the selected value string
Group name, required, disabledUnset / falseForm name and group constraints
Group orientation, dir, loopRadix defaults; loop trueKeyboard navigation configuration
Item valueRequiredUnique value within the group
Item disabled, aria-invalidUnsetAvailability and invalid state
Radix Root / Item props—Includes refs and accessibility attributes

Use Checkbox for multiple independent selections and Switch for an immediate on/off setting.

On this page