Radio Group
Choose exactly one option from a small set of visible choices.
@garn/ui/radio-groupDefault
Three labeled options, one preselected.
Sizing
Radio dot size (fixed --garn-box-* geometry, identity); set on the root, propagated to items.
smmdlgStates
Interactive states, toggled live.
<RadioGroup>
<div className="flex items-center gap-2"><RadioGroupItem value="a" id="a" /><Label htmlFor="a">One</Label></div>
<div className="flex items-center gap-2"><RadioGroupItem value="b" id="b" /><Label htmlFor="b">Two</Label></div>
</RadioGroup>State
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add radio-group- Registry
radio-group- Source
- radio-group.tsx
- Deps
@radix-ui/react-radio-groupclass-variance-authoritylucide-react- Registry deps
utils
Import
import { RadioGroup } from "@garn/ui/radio-group";Props
Generated from the component's TypeScript types.
size- Description
- No description.
- Type
"lg" | "md" | "sm"- Default
md
Plus 288 inherited native HTML attributes.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="radio-group"]| Property | Token | Tier |
|---|---|---|
size | --garn-box-md | semantic · identity |
fill | --garn-brand-solidbrandable | semantic |
ring | --garn-ringbrandable | semantic |
Overview
RadioGroup lets a person pick exactly one option from a few mutually-exclusive choices that are all worth showing at once (≈2–5). RadioGroup owns the selected value and propagates size to each RadioGroupItem. Once the list grows past a handful or the options stop fitting on screen, switch to Select; for a binary on/off setting, a Switch or single Checkbox reads better than two radios.
Guidelines
Always show one option as selected. A radio group should have a sensible default rather than starting empty — an all-blank group makes "no choice" look like a valid state when it usually isn't. Give each RadioGroupItem a unique value and its own Label.
Keep options parallel and exhaustive. Phrase choices in the same grammatical form and at the same level of specificity, and cover the full space (add an "Other"/"None" when the set isn't complete). Order them logically — by magnitude, frequency, or convention — not at random.
Don't use radios for multi-select or instant actions. Several selectable items → Checkboxes; a setting that takes effect immediately → Switch. Arrow keys move selection within the group (roving focus), so don't nest interactive controls inside an item.
Best practices
- Give every RadioGroupItem a unique value and a clickable Label.
- Pre-select a sensible default with defaultValue when one exists.
- Don't use radios for many options — switch to a select past ~5.
- Don't use radios for multi-select — that's checkboxes.
Content guidelines
- Write parallel option labels in sentence case (“Standard”, “Express”, “Overnight”).
- Order options logically (by speed, price, or frequency) and lead with the most common.
- Add a short helper line to an option only when the trade-off isn't obvious from the label.
Accessibility
- Role
radiogroup- ARIA APG
- radio group
- Focus
- Roving tabindex; arrow keys move + select within the group.
Enforceable contracts
Label the group and each option (a Label per item, plus a group label).
when the group has no accessible name (aria-labelledby / aria-label) and items have no labels
Keyboard
| Tab | Move focus into the group (lands on the selected, or first, radio). |
| ArrowUpArrowDownArrowLeftArrowRight | Move to and select the next/previous option. |
- • role=radiogroup wraps role=radio items; label the group (aria-labelledby / a Label).
- Status
- Stable
- Version
v0.3.0- Introduced
v0.1.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.