Radio Group
A set of mutually exclusive options where exactly one can be selected, built on Radix RadioGroup. Sizes line up pixel-for-pixel with Checkbox, so radios and checkboxes sit flush in the same form.
Installation#
Usage#
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function Example() {
return (
<RadioGroup defaultValue="pro">
<label htmlFor="pro" className="flex items-center gap-2.5">
<RadioGroupItem id="pro" value="pro" />
Pro
</label>
</RadioGroup>
)
}Sizes#
sm (16px) matches the dense table checkbox; md (20px) is the default for forms. Set size on the group and every item inherits it through context.
States#
Disable a single RadioGroupItem and roving focus skips it, or disable the whole RadioGroup at once.
With descriptions#
Give each option a line of supporting text with RadioCardDescription. The whole card is the radio, so the entire surface is the hit target: selected, it borders brand, lifts the accent halo and pops its icon, exactly like the plan picker below.
Cards#
Reach for RadioCard when each option deserves an icon and a line of supporting text, the affordance behind a plan, theme or payment-method picker. The card is the radio, so keyboard and focus come for free; selected, it borders brand and lifts the accent halo while the flooded dot tweens in.
Card sizes#
md (the default, above) suits a title plus a line of description. Drop a RadioCard to size="sm" when the option is a single line, a title on its own or an icon and text, so it doesn't float in dead space. The padding, control and radius all tighten together, the row centers vertically, and the title drops to medium; the control still lines up with the standalone radio.
Swatches#
RadioSwatch dresses a radio as a colour chip, the picker on a product page. The chip is filled with its color (any CSS colour: a product's colour is data, not a theme role), keeps a hairline edge so a pale colour never dissolves into the page, and takes a fine ink ring, cut off the chip by a gap in the ground's own colour, when chosen. The ring is ink rather than brand on purpose: the chip's colour is the content, so a brand ring would add a colour the product doesn't have. Keyboard focus is a separate brand outline outside it, so focus and selection never look alike. It has no visible text, so label is required: it is the name a screen reader announces. Show the chosen name in the legend for everyone else, and lay the group out as a row.
Swatch sizes#
Swatches follow the group's size: sm is 24px for a product card or a filter, md is 32px for a product page. Either way the hit target grows to 40px (44 on touch), so keep at least an 8px gap between chips. A disabled swatch fades and roving focus skips it; say why in its label ("Clay, sold out").
Controlled#
Pass value and onValueChange to own the selection. The group lays out horizontally here with a grid-flow-col override on className.