Radio Group
A set of mutually exclusive radio buttons built on Base UI. Three sizes, with automatic invalid styling inside a Field.
Playground
<RadioGroup defaultValue="option-1">
<div className="flex items-center gap-4">
<RadioGroupItem value="option-1" />
<RadioGroupItem value="option-2" />
</div>
</RadioGroup>Preview
Wrap RadioGroupItems in a RadioGroup and give each a value. Use defaultValue for the initial selection.
<RadioGroup defaultValue="option-1">
<div className="flex items-center gap-4">
<RadioGroupItem value="option-1" />
<RadioGroupItem value="option-2" />
</div>
</RadioGroup>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/radio-group.jsonUsage
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"<RadioGroup defaultValue="comfortable" onValueChange={(value) => console.log(value)}>
<RadioGroupItem value="compact" />
<RadioGroupItem value="comfortable" />
</RadioGroup>Sizes
size on the item scales the circle and its dot: xs (13px), sm (14px) and default (16px).
<RadioGroup defaultValue="a">
<RadioGroupItem size="xs" value="a" />
<RadioGroupItem size="xs" value="b" />
</RadioGroup>
<RadioGroup defaultValue="a">
<RadioGroupItem size="sm" value="a" />
<RadioGroupItem size="sm" value="b" />
</RadioGroup>
<RadioGroup defaultValue="a">
<RadioGroupItem value="a" />
<RadioGroupItem value="b" />
</RadioGroup>Disabled
Set disabled on the group (or a single item) – items become non-interactive with muted checked and unchecked styling.
<RadioGroup defaultValue="dis-2" disabled>
<div className="flex items-center gap-4">
<RadioGroupItem value="dis-1" />
<RadioGroupItem value="dis-2" />
</div>
</RadioGroup>Invalid
Set data-invalid="true" on an item for a destructive border and ring – or place the group inside a Field data-invalid="true" and every item inherits the invalid styling from the field context.
<RadioGroup value="">
<RadioGroupItem data-invalid="true" value="inv-1" />
</RadioGroup>
<RadioGroup value="inv-2">
<RadioGroupItem data-invalid="true" value="inv-2" />
</RadioGroup>API reference
RadioGroup wraps the Base UI radio group and accepts all of its props; RadioGroupItem wraps the radio root and renders its own indicator dot. Both accept className.
RadioGroup
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | – | Controlled value of the selected item. |
| defaultValue | string | – | Initially selected value when uncontrolled. |
| onValueChange | (value, eventDetails) => void | – | Called when the selection changes. |
| disabled | boolean | false | Disables every item in the group. |
| name | string | – | Name submitted with the owning form (renders a hidden input). |
RadioGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | – | The value this radio represents within the group. Required. |
| size | "xs" | "sm" | "default" | "default" | Circle size – 13px, 14px or 16px, with a matching indicator dot. |
| disabled | boolean | false | Disables this item only. |
| data-invalid | string | – | Set to "true" for destructive border and ring styling on this item. |
| Component | Description |
|---|---|
| RadioGroup | Group container (data-slot="radio-group"), rendered with role="radiogroup" and a grid gap-2 layout. |
| RadioGroupItem | The radio control (data-slot="radio-group-item", role="radio"). Reflects size as data-size and state as data-checked / data-unchecked / data-disabled. Includes an enlarged invisible hit area. |
Accessibility & styling hooks
Base UI provides the radiogroup/radio roles with arrow-key navigation between items, and a hidden input for form submission when name is set. Style against the state attributes – data-checked, data-unchecked, data-disabled, data-invalid and data-size – or reuse the exported radioGroupItemVariants cva helper for custom radio surfaces.