Radio Group

A set of radio buttons where exactly one option can be chosen.

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import { Label } from '@/components/ui/label'

export default function RadioGroupDemo() {
  return (
    <RadioGroup defaultValue="comfortable" aria-label="Density">
      <div className="flex items-center gap-2">
        <RadioGroupItem id="radio-demo-default" value="default" />
        <Label htmlFor="radio-demo-default">Default</Label>
      </div>
      <div className="flex items-center gap-2">
        <RadioGroupItem id="radio-demo-comfortable" value="comfortable" />
        <Label htmlFor="radio-demo-comfortable">Comfortable</Label>
      </div>
      <div className="flex items-center gap-2">
        <RadioGroupItem id="radio-demo-compact" value="compact" />
        <Label htmlFor="radio-demo-compact">Compact</Label>
      </div>
    </RadioGroup>
  )
}

Built on Base UI

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/radio-group.json

Needs a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.

Radio Group imports cn() from lib/utils.ts — add it too if you don't have it yet:

import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Usage

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import { Label } from '@/components/ui/label'

<RadioGroup defaultValue="comfortable" aria-label="Density">
  <div className="flex items-center gap-2">
    <RadioGroupItem id="r1" value="default" />
    <Label htmlFor="r1">Default</Label>
  </div>
  <div className="flex items-center gap-2">
    <RadioGroupItem id="r2" value="comfortable" />
    <Label htmlFor="r2">Comfortable</Label>
  </div>
</RadioGroup>

Examples

Cards with descriptions

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'

const plans = [
  { value: 'starter', name: 'Starter', description: 'For a single portfolio.' },
  { value: 'studio', name: 'Studio', description: 'For a small team with shared projects.' },
  { value: 'archive', name: 'Archive', description: 'Read-only, for finished work.', disabled: true },
]

export default function RadioGroupCards() {
  return (
    <RadioGroup defaultValue="studio" aria-label="Plan" className="w-full max-w-sm">
      {plans.map(plan => (
        <label
          key={plan.value}
          className="flex cursor-pointer items-start gap-3 rounded-lg border border-border p-4 transition-colors has-[[data-checked]]:border-primary has-[[data-disabled]]:cursor-not-allowed has-[[data-disabled]]:opacity-50"
        >
          <RadioGroupItem value={plan.value} disabled={plan.disabled} className="mt-0.5" />
          <span className="grid gap-1">
            <span className="text-sm leading-none font-medium">{plan.name}</span>
            <span className="text-sm text-muted-foreground">{plan.description}</span>
          </span>
        </label>
      ))}
    </RadioGroup>
  )
}

API Reference

NameTypeDefaultDescription
value / onValueChangeunknown / (value: unknown) => void—Controlled selected value (set on RadioGroup).
defaultValueunknown—Initially selected value (uncontrolled).
namestring—Identifies the group when a form is submitted.
requiredbooleanfalseThe visitor must choose a value before submitting a form.
disabledbooleanfalseIgnores user interaction (on RadioGroup, or on a single RadioGroupItem).
RadioGroupItem valueunknown—The value this radio stands for. Required.
Keyboard——Arrow keys move the selection; Tab enters and leaves the group as one stop.