Radio group
One choice from a short, visible set.
Installation
pnpm --filter your-app add "@commenda/pathfinder@workspace:*"Import @commenda/pathfinder/styles.css once at the app root. The stylesheet is precompiled with Tailwind v4; your application does not need Tailwind or source scanning. Event handlers belong in a client component in Next.js App Router.
Usage
import { RadioGroup } from '@commenda/pathfinder/radio-group';
<RadioGroup
label="Filing frequency"
name="frequency"
value={frequency}
onValueChange={setFrequency}
options={[
{ value: 'annual', label: 'Annual' },
{ value: 'quarterly', label: 'Quarterly' },
{ value: 'monthly', label: 'Monthly' },
]}
/>;| Prop | Type | Default / behavior |
|---|---|---|
label | string | Required group name, visible by default |
hideLabel | boolean | false; hides only the visible group heading |
description | string | Optional group guidance |
options | readonly RadioOption[] | Required; stable, unique string values |
value | string | null | Controlled selected value; null means intentionally unanswered |
defaultValue | string | Uncontrolled initial selection; omitted means unanswered |
onValueChange | (value: string) => void | Required with controlled value, optional when uncontrolled |
variant | 'default' | 'card' | 'default' |
orientation | 'vertical' | 'horizontal' | 'vertical'; horizontal layout wraps and cards share row height |
disabled | boolean | Disables interaction for the control or group. |
readOnly | boolean | Keeps the current value visible while preventing changes. |
required | boolean | Requires a value for native form validation. |
name | string | Name used when the control submits its value with a form. |
form | string | ID of the form associated with the control. |
inputRef | Ref<HTMLInputElement> | Access to the underlying form input. |
className | string | Additional class names for the outer layout. |
ref | Ref<HTMLDivElement> | Access to the interactive root element. |
| Native events and ARIA | Base UI group props | Typed passthrough |
RadioOption:
| Property | Type | Purpose |
|---|---|---|
value | string | Required stable, unique identity and submitted value |
label | string | Required option name |
description | string | Supporting explanation |
details | readonly string[] | Additional card bullets |
disabled | boolean | Unavailable option; keyboard navigation skips it |
disabledReason | string | Visible and associated while the option or whole group is disabled |
Use two to five visible options. Prefer a sensible default, but permit an empty group when explicitly choosing is necessary. Do not auto-select the first item or silently replace a removed controlled value. The owner reconciles changing options. Labels select their option; arrow keys move selection, and only one value submits. For longer lists use Select. Never use one radio for a boolean setting.
Radio cards use variant="card"; they are the same radio group, not an unrelated clickable card API. Figma calls its collection “Radio card” but includes checkbox cards; those belong to Checkbox to preserve multiple-selection semantics. Cards have 16px padding, 12px control/text gap, 8px radius and 13px medium labels. Their width adapts from the 320px Figma specimen.
Examples
Descriptions
Radio cards
Disabled group
Read the Figma choice-control rules for design guidance, source discrepancies and accessibility requirements.
Design rules
Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.
Radio and cards
Source: 199:3, radio variants 200:46, card variants 201:413, guidance 205:320.
- RADIO-01 — One choice from two to five visible options. Use Select for longer lists or limited space. A lone boolean option uses Checkbox/Switch. Arrow keys move selection and skip disabled items; Tab enters/leaves the group.
- RADIO-02 — Prefer a sensible default. Leave the group unanswered only when deliberate choice is required. Never silently choose the first value or replace a removed controlled value. The application reconciles dynamic options.
- RADIO-03 — Order options by frequency, size or time rather than alphabetically by default. Circle 16px, selected white dot 6px; colors and focus match Checkbox. Group row gap 8px.
- CARD-01 — Use a card when each option needs title and description. Keep cards in one row equal-height. The “Radio card” Figma collection contains both radio and checkbox controls; Pathfinder exposes
RadioGroup variant="card"for one choice andCheckbox variant="card"for independent choices. - CARD-02 — Card padding 16px, control/text gap 12px, radius 8px. Title Label/13 Strong; description Copy/12 with 4px gap. Detail bullets have 2px gap and 4px top padding. Surface remains white when selected; border becomes blue-700. Focus surrounds the whole card. Disabled surface/border/text use soft-pearl-100/300/600. The 320px specimen width adapts to the container.
Implementation decisions and source differences
The complete prop tables are on Checkbox, RadioGroup and Switch. Source rule IDs are also kept in the component implementation comments and exported through llms.txt, llms-full.txt and the Markdown routes.
-
CHOICE-01 — The sheets describe 8px list gaps but some documentation frames place rows 32px apart. Use the documented 8px component-list gap; documentation specimen whitespace is not a new size token.
-
CHOICE-02 — Built-in text is plain, wrapping content. Do not place links, buttons or nested interactive controls inside labels or cards. Disabled reasons are visible descriptions, not tooltip-only explanations on controls removed from keyboard navigation.
-
CHOICE-03 — Visual control size is not the hit target. Coarse-pointer rows provide at least 44px height, while preserving 16px marks and the 36×20px switch track. Cards already exceed this height.
-
CHOICE-04 — Hover/focus are real browser states, not public cosmetic props. Retain native
name,value,form,required,readOnly, disabled semantics and input refs.hideLabelpreserves the required accessible label. -
CHOICE-05 — Use Pathfinder's existing Check/Minus optical artwork at 12px. Boxes, circles, tracks and thumbs are interactive primitive geometry, styled with the Figma tokens; they are not flattened screenshots. This keeps focus, RTL and switch movement functional.