v0.5

Radio

Single-choice form control for mutually-exclusive options inside a RadioGroup.

Description

Radio is a single item within a radio group. It is always rendered inside a RadioGroup; the group owns the selected value, the roving tab index, and arrow-key navigation. On its own a Radio cannot toggle, which is by design: a single radio is never the right control.

Reach for it when you have two to six mutually-exclusive options that should all be visible at once: a plan picker, a theme switcher, a sort order. For more than six options use Select; for binary on/off use Switch; for one-of-many that allows multiple use CheckboxGroup.

Don't use Radio for a standalone yes/no answer; a single radio that can't be unselected is a usability dead-end. Use Checkbox instead.

Installation

pnpm dlx @create-ui/cli add radio

Usage

import { Radio } from "@/components/ui/radio"
import { RadioGroup } from "@/components/ui/radio-group"
<RadioGroup defaultValue="a">
  <Radio value="a" />
  <Radio value="b" />
</RadioGroup>

Examples

Variants

variant picks the semantic intent of the selected indicator. primary is the default; use danger for a destructive option (e.g. "Delete account") and inverse on dark surfaces.

Sizes

Three sizes line up with the rest of the form-control scale. sm is the default; drop to xs in dense rows, or use md for more spacious layouts.

States

The radio exposes four runtime states (unchecked, checked, disabled, and disabled-checked) through the Radix data-state and data-disabled attributes.

Inside RadioGroup

When variant and size are passed on the group, every child Radio inherits them through RadioContext. Pass styling once on the parent, not on each item.

Children inherit variant and size from the group via context — pass them on the group, not each child.

Accessibility

Radio is built on Radix UI's RadioGroup.Item, so keyboard navigation, focus management, and ARIA wiring are handled for you. Focus management is roving: only the checked (or first) item is in the tab order.

KeyDescription
TabMoves focus into the group at the checked (or first) item.
SpaceSelects the focused radio.
ArrowDown / ArrowRightMoves focus to and selects the next radio in the group.
ArrowUp / ArrowLeftMoves focus to and selects the previous radio in the group.

ARIA notes:

  • The root renders with role="radio" and sets aria-checked to "true" or "false".
  • disabled sets data-disabled and skips the item during arrow-key navigation.
  • The indicator dot is decorative; expose the radio's purpose via aria-label, aria-labelledby, or a <label htmlFor> association.

Styling

Tailwind override: pass className to merge Tailwind classes with the component's CVA classes:

<Radio value="a" className="size-7" />

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="radio" on the root element.
  • data-slot="radio-indicator" on the inner indicator wrapper.
  • data-variant="<variant>", data-size="<size>" on the root.
  • data-state="checked" | "unchecked" (managed by Radix) and data-disabled (only when disabled).

Target a specific state in CSS:

[data-slot="radio"][data-state="checked"] {
  /* … */
}
  • RadioGroup: the required parent; owns the selected value and arrow-key navigation.
  • Checkbox: single binary control when there isn't a mutually-exclusive set.
  • Select: use instead of RadioGroup when there are more than six options.
  • Switch: immediate on/off setting.

API Reference

Radio

A single radio item. Extends React.ComponentProps<typeof Radix.RadioGroup.Item>, so any prop the Radix primitive accepts (value, id, disabled, required, …) is forwarded.

Props

PropTypeDefaultDescription
valuestring-The value submitted when this radio is selected. Required.
idstring-DOM id, used to pair with <label htmlFor>.
disabledbooleanfalseDisables interaction and skips the item during arrow-key navigation.
requiredbooleanfalseMarks the item as required (used when the surrounding form validates on submit).
classNamestring-Tailwind classes merged with the component's CVA classes.

Variants

VariantOptionsDefaultDescription
variant"primary" "neutral" "danger" "success" "inverse""primary"Semantic color intent for the selected indicator and ring.
size"xs" "sm" "md""sm"Size scale; controls outer circle, indicator, and border width.