Radio Group

A set of mutually exclusive radio options. Built on Radix UI RadioGroup with roving focus and arrow-key navigation.

Vertical

Horizontal

With descriptions

$12 / month · cancel anytime.

$120 / year · save two months.

With disabled option

Installation

pnpm
pnpm dlx @hex-core/cli add radio-group

Card-style tiles

Wrap each option in a Label so the entire card becomes the click target. Canonical plan-tier or upgrade picker.

tsx
<RadioGroup defaultValue="pro" className="grid gap-3 sm:grid-cols-3">
  <Label
    htmlFor="plan-starter"
    className="flex cursor-pointer flex-col gap-1 rounded-lg border border-input p-4 shadow-sm transition-colors hover:border-ring/50 has-[[data-state=checked]]:border-primary has-[[data-state=checked]]:bg-accent/40"
  >
    <div className="flex items-center justify-between">
      <span className="text-sm font-semibold">Starter</span>
      <RadioGroupItem value="starter" id="plan-starter" />
    </div>
    <span className="text-xs text-muted-foreground">For solo developers exploring the platform.</span>
    <span className="mt-1 text-sm font-medium">$0/mo</span>
  </Label>
  <Label
    htmlFor="plan-pro"
    className="flex cursor-pointer flex-col gap-1 rounded-lg border border-input p-4 shadow-sm transition-colors hover:border-ring/50 has-[[data-state=checked]]:border-primary has-[[data-state=checked]]:bg-accent/40"
  >
    <div className="flex items-center justify-between">
      <span className="text-sm font-semibold">Pro</span>
      <RadioGroupItem value="pro" id="plan-pro" />
    </div>
    <span className="text-xs text-muted-foreground">For small teams shipping production apps.</span>
    <span className="mt-1 text-sm font-medium">$29/mo</span>
  </Label>
  <Label
    htmlFor="plan-enterprise"
    className="flex cursor-pointer flex-col gap-1 rounded-lg border border-input p-4 shadow-sm transition-colors hover:border-ring/50 has-[[data-state=checked]]:border-primary has-[[data-state=checked]]:bg-accent/40"
  >
    <div className="flex items-center justify-between">
      <span className="text-sm font-semibold">Enterprise</span>
      <RadioGroupItem value="enterprise" id="plan-enterprise" />
    </div>
    <span className="text-xs text-muted-foreground">SSO, audit logs, and a dedicated support channel.</span>
    <span className="mt-1 text-sm font-medium">Contact sales</span>
  </Label>
</RadioGroup>

With descriptions inline

Notification frequency picker — each option pairs a primary label with a secondary description for context.

tsx
<RadioGroup defaultValue="mentions" className="grid gap-4">
  <div className="flex items-start gap-3">
    <RadioGroupItem value="all" id="freq-all" className="mt-1" />
    <div className="grid gap-0.5">
      <Label htmlFor="freq-all" className="font-medium">All activity</Label>
      <p className="text-sm text-muted-foreground">Email me whenever anything happens in this workspace.</p>
    </div>
  </div>
  <div className="flex items-start gap-3">
    <RadioGroupItem value="mentions" id="freq-mentions" className="mt-1" />
    <div className="grid gap-0.5">
      <Label htmlFor="freq-mentions" className="font-medium">Mentions only</Label>
      <p className="text-sm text-muted-foreground">Email me only when I am @-mentioned or assigned.</p>
    </div>
  </div>
  <div className="flex items-start gap-3">
    <RadioGroupItem value="none" id="freq-none" className="mt-1" />
    <div className="grid gap-0.5">
      <Label htmlFor="freq-none" className="font-medium">Nothing</Label>
      <p className="text-sm text-muted-foreground">Stay quiet. I will check the workspace manually.</p>
    </div>
  </div>
</RadioGroup>

API Reference

PropTypeDefaultDescription
value
stringControlled selected value
defaultValue
stringDefault selected value for uncontrolled usage
onValueChange
functionCallback on value change: (value: string) => void
disabled
booleanfalseDisable all items
name
stringForm field name (for native form submission)
orientation
"horizontal" | "vertical"verticalLayout direction

AI Guidance

When to use

Use for mutually exclusive choices from a short list (2-5 options) where all options should be visible. Pair each RadioGroupItem with a Label.

When not to use

Don't use for many options (use Select). Don't use for boolean toggles (use Switch or Checkbox). Don't use for multi-select.

Common mistakes

  • Missing Label for each RadioGroupItem
  • Using for more than 5 options (use Select)
  • Using htmlFor id mismatch between Label and RadioGroupItem

Accessibility

Radix implements the WAI-ARIA radio group pattern. Arrow keys move focus+selection. Radix handles aria-checked, role='radiogroup', role='radio'.

Related components

Token budget: 400