A set of checkable buttons—known as radio buttons—where only one can be selected at a time.
npx shadcn@latest add https://sdk-components.thesqd.com/r/radio-group.jsonimport { RadioGroup } from "@/components/ui/radio-group";import { RadioGroup } from "@/components/ui/radio-group";
export function Example() {
return (
<RadioGroup
defaultValue="comfortable"
options={[
{ value: "default", label: "Default" },
{ value: "comfortable", label: "Comfortable" },
{ value: "compact", label: "Compact (disabled)", disabled: true },
]}
/>
);
}RadioGroup (single component — pass options as data)
├── type="default" | "card" | "pill" | "chip" | "tile"
├── options={[
│ { value, label, caption?, meta?, icon?, disabled? },
│ …
│ ]}
└── otherOption={{ value, label, caption?, placeholder? }}
+ otherValue / onOtherValueChange / defaultOtherValue
variant rendering:
default → bare radios + labels (rows)
card → full-width bordered card per option (label + caption + meta)
pill → content-width compact card (radio + label, wraps inline)
chip → borderless tile (label + optional meta line, wraps inline)
tile → large icon-led card (icon + label + caption, centered)
For multi-select, see <MultiSelect /> in @/components/ui/multi-select
(documented on the /multi-select page) — same flat options shape, with
type="cards" or type="chip-group".
Slot exports — RadioGroupItem, RadioGroupCard, RadioGroupCardLabel,
RadioGroupCardDescription — remain as the escape hatch for fully custom
layouts.Select shoe size
How did you hear about us?
What team are you on?
This field is required
We'll only use this for important project updates.
RadioGroup
| Prop | Type | Default | Description |
|---|---|---|---|
options | RadioGroupOption[] | — | List of options to render. Without this prop, RadioGroup stays compound (drop in `<RadioGroupItem>` children manually). |
type | "default" | "card" | "pill" | "chip" | "tile" | "default" | Variant. `default` is bare radios. `card` wraps each option in a bordered row with optional `meta` / `description`. `pill` and `chip` are single-row h-9 selectors. `tile` is a square tile with a centered label. (Legacy alias: `variant` — still accepted.) |
cols | number | — | Number of columns. For `card` / `tile`, omitting it wraps responsively (auto-fill, min 16rem per card). For `pill`, sets a fixed grid of equal-width pills (e.g. `cols={2}`); ignored when `wrap` is set. |
wrap | boolean | false | `pill` only. Flow pills in a wrapping inline row sized to each label instead of a fixed grid. Wins over `cols`, and is the default for `pill` when neither is set. |
value | string | — | Controlled selected value. Pair with `onValueChange`. |
defaultValue | string | — | Uncontrolled initial value. |
onValueChange | (value: string) => void | — | Fires when the selected radio changes. |
name | string | — | Form field name (rendered as a hidden input). |
disabled | boolean | — | Disables every radio in the group. |
error | boolean | string | — | Error state. `true` marks items invalid (red ring); a string also renders the inline `text-xs mt-1.5 text-red-500` message below the group. |
caption | ReactNode | — | Helper copy shown below the group via FieldHint. Error wins when both are present. |
className | string | — | Override the wrapper layout (defaults to `grid w-full gap-2`). |
detailValues | Record<string, string> | — | Card variant only. Controlled `option.value → detail text` map for options flagged `requiresDetail`. |
defaultDetailValues | Record<string, string> | — | Card variant only. Uncontrolled initial detail-text map. |
onDetailChange | (next: Record<string, string>) => void | — | Card variant only. Fires when the revealed detail textarea changes. |
RadioGroupOption
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Value reported when the option is selected. |
label | ReactNode | — | Visible label rendered next to the radio. |
caption | ReactNode | — | Helper text — only rendered when `type="card"`. |
meta | ReactNode | — | Right-aligned secondary text (e.g. `"Free"`, `"$5"`) — card variant only. |
requiresDetail | boolean | — | Card variant only. Selecting this option reveals a required textarea beneath it, tied back with an elbow connector. Honored at `cols` 1 or 2. |
detailLabel | string | — | Label above the revealed detail textarea. Defaults to "Provide more details". |
detailPlaceholder | string | — | Placeholder for the revealed detail textarea. |
lastUsed | boolean | false | Card variant only. Floats a built-in amber "Last used" pill on the card's top border — no `<Badge>` import needed. |
badge | ReactNode | — | Card variant only. Custom pill floated on the card's top border (e.g. `<Badge type="solid" size="xxs">Most popular</Badge>`). Renders alongside `lastUsed` when both are set. |
image | string | — | Card variant only. Image URL rendered as the leading square thumbnail. |
imageAlt | string | — | Alt text for `image`. |
swatch | ReactNode | — | Card variant only. Custom leading visual (gradient, icon, …) — wins over `image`. |
tags | { icon?: ReactNode; image?: string; label?: ReactNode }[] | — | Card variant only. Icon/label row under the caption — the icons render as an overlapping circular stack (hovering one lifts it and shifts its neighbors with a distance falloff, transitions.dev #11), labels joined with `·`. Pass `image` (e.g. `/brand/departments/circle-graphic.svg`) for a pre-drawn circular asset instead of `icon` JSX — it renders full-bleed with no border ring, and the label doubles as its `alt`/`title`. |
aside | ReactNode | — | Card variant only. Block pinned to the card's right edge (price stack, badge column, …). Rendered as-is. |
titleBadge | ReactNode | — | Card variant only. Badge or link rendered inline just to the right of the card's label. |
features | ReactNode[] | — | Card variant only. Check-list that expands open inside the card when the option is selected (animated 0fr→1fr grid reveal). Cards with `features`, `aside`, or `tags` also pin the radio to the top-left instead of centering it. |
featuresTitle | ReactNode | — | Small uppercase heading above the revealed `features` list. |
disabled | boolean | — | Disable this individual option. |