Single-choice group with roving focus and a selected dot that glides between options on a spring; card mode turns options into tiles a volt ring slides across.
radioformradio groupradio cardsplan pickerchoice
Installation
$npx shadcn@latest add @geturui/radio-group
Usage
usage.tsx
1import { Radio, RadioGroup } from "@/components/ui/radio-group";
2
3export function BillingCycle() {
4 return (
5 <>
6 <RadioGroup label="Billing cycle" defaultValue="annual">
7 <Radio value="monthly" label="Monthly" hint="$19 per seat, cancel any time." />
8 <Radio value="annual" label="Annual" hint="$15 per seat, billed once a year." />
9 </RadioGroup>
10
11 <RadioGroup label="Choose a plan" variant="card" orientation="horizontal" defaultValue="pro">
12 <Radio value="free" label="Free" price="$0" hint="Every free component." />
13 <Radio value="pro" label="Pro" meta="per year" price="$129" hint="All Pro blocks and templates." />
14 </RadioGroup>
15 </>
16 );
17}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | — | Visible group label; names the radiogroup. Use aria-label when there is none. |
value / defaultValue | string | null | — | Controlled or uncontrolled selected value. |
onValueChange | (value: string) => void | — | Called when a radio is picked by click, Space or the arrow keys. |
size | "sm" | "md" | "lg" | "md" | 16, 20 or 24px indicator, shared with every Radio. Card padding scales too. |
orientation | "vertical" | "horizontal" | "vertical" | A column or a wrapping row; cards become a responsive grid. |
variant | "default" | "card" | "default" | Card mode renders selectable tiles with a gliding volt ring and lift. |
indicator | "check" | "radio" | "none" | "check" | Card mode: the mark in the corner of each card. |
hint / error | ReactNode | — | Line under the group. Any error marks every radio invalid and is announced. |
disabled / required / name | boolean / boolean / string | — | Disable the whole group, require a choice, and set the form field name. |
Radio value* | string | — | The option's value. |
Radio label / hint | ReactNode | — | Option text and supporting line (cards: title and description). |
Radio disabled | boolean | false | Disable one option; arrow keys skip it. |
Radio icon / meta / price / badge / footer | ReactNode | — | Card slots. footer renders below the card body, outside the click target, for actions like Edit. |
RadioIndicator | { checked, size?, invalid?, layoutId? } | — | The drawn circle on its own, for custom rows and tables. |
Accessibility
- Every option, cards included, is a native <input type="radio">, so forms submit it and screen readers report position and state.
- One tab stop on the checked (or first enabled) radio; arrows move and select with wrap-around, Home and End jump to the ends, disabled options are skipped.
- Hints are linked with aria-describedby; group errors carry an icon and are linked to the radiogroup.
- Under reduced motion the dot and ring crossfade instead of gliding, and cards no longer lift.