import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export default function RadioGroupDemo() {
return (
<RadioGroup defaultValue="comfortable" className="gap-3">
<div className="flex items-center gap-3">
<RadioGroupItem value="default" id="radio-default" />
<Label htmlFor="radio-default">Default</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="comfortable" id="radio-comfortable" />
<Label htmlFor="radio-comfortable">Comfortable</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="compact" id="radio-compact" />
<Label htmlFor="radio-compact">Compact</Label>
</div>
</RadioGroup>
)
}Installation
npx logic2b@latest add radio-groupWorking with an AI assistant? Copy this prompt into Claude Code, Cursor or Copilot — it carries the install steps, a no-CLI fallback and a verification checklist.
Add the "radio-group" item from the logic2b ui registry (https://ui.logic2b.com) to this project. Follow every step and verify at the end. ## Steps 1. If the project has no `components.json` yet, set up logic2b ui first: ```bash npx logic2b@latest init ``` 2. Install the item (the CLI resolves registry dependencies automatically): ```bash npx logic2b@latest add radio-group ``` 3. Install any npm dependencies the command prints. ## If the CLI is not available Do it manually from the registry payload: 1. Fetch https://ui.logic2b.com/r/radio-group.json. 2. Write every entry in `files[]` to its mapped project path (see below). 3. Repeat (recursively) for each name in `registryDependencies`. 4. Install every package listed in `dependencies` across those payloads. ## Registry reference - Index of every item: https://ui.logic2b.com/r/index.json - Item payload (full source): https://ui.logic2b.com/r/<name>.json - Usage examples per item: https://ui.logic2b.com/r/demos/index.json → https://ui.logic2b.com/r/demos/<demo>.json - Docs index for agents: https://ui.logic2b.com/llms.txt (full docs: https://ui.logic2b.com/llms-full.txt) - Every docs page is Markdown when you append `.md` to its URL. Registry file paths map to project paths like this: - `ui/*` → `@/components/ui/*` - `blocks/<name>/*` → `@/components/*` - `charts/*` → `@/components/charts/*` - `hooks/*` → `@/hooks/*` - `lib/utils.ts` → `@/lib/utils.ts` - `theme.css` → next to the project's Tailwind entry stylesheet ## Conventions (do not break these) - Tailwind CSS v4 (CSS-first config; no tailwind.config.js needed) and React 19. - All colors go through semantic tokens (`bg-primary`, `text-muted-foreground`, `border-border`, …). Never hardcode hex/oklch values in components. - Dark mode is class-based: toggle `.dark` on `<html>`. - Icons come from lucide-react. ## Verify before finishing 1. The dev server starts and the app renders without console errors. 2. TypeScript compiles (`tsc --noEmit` or the framework's check). 3. Components use the theme: a `<Button>` shows the primary token color, and toggling `.dark` on `<html>` switches the palette.
Install the dependencies:
npm install radix-ui lucide-reactCopy into ui/radio-group.tsx:
"use client"
import * as React from "react"
import { RadioGroup as RadioGroupPrimitive } from "radix-ui"
import { CircleIcon } from "lucide-react"
import { cn } from "@/lib/utils"
function RadioGroup({
className,
...props
}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
return (
<RadioGroupPrimitive.Root
data-slot="radio-group"
className={cn("grid gap-3", className)}
{...props}
/>
)
}
function RadioGroupItem({
className,
...props
}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
return (
<RadioGroupPrimitive.Item
data-slot="radio-group-item"
className={cn(
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<RadioGroupPrimitive.Indicator
data-slot="radio-group-indicator"
className="relative flex items-center justify-center"
>
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
)
}
export { RadioGroup, RadioGroupItem }Usage
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
<RadioGroup defaultValue="comfortable">
<RadioGroupItem value="default" id="r1" />
<RadioGroupItem value="comfortable" id="r2" />
</RadioGroup>
API
| Prop | Type | Default |
|---|---|---|
value / defaultValue (RadioGroup) |
string |
— |
onValueChange (RadioGroup) |
(value: string) => void |
— |
orientation (RadioGroup) |
horizontal | vertical |
vertical |
disabled (RadioGroup) |
boolean |
false |
value (RadioGroupItem) |
string — required |
— |
disabled (RadioGroupItem) |
boolean |
false |
Examples
Cards
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
const plans = [
{ value: "starter", title: "Starter", desc: "For side projects." },
{ value: "pro", title: "Pro", desc: "For growing teams." },
]
export default function RadioGroupCardsDemo() {
return (
<RadioGroup defaultValue="pro" className="w-full max-w-sm gap-3">
{plans.map((plan) => (
<Label
key={plan.value}
htmlFor={`plan-${plan.value}`}
className="flex items-start gap-3 rounded-md border p-3 has-[[data-state=checked]]:border-primary"
>
<RadioGroupItem
value={plan.value}
id={`plan-${plan.value}`}
className="mt-0.5"
/>
<div className="grid gap-1">
<span className="font-medium">{plan.title}</span>
<span className="text-muted-foreground font-normal">
{plan.desc}
</span>
</div>
</Label>
))}
</RadioGroup>
)
}With a disabled option
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export default function RadioGroupDisabledDemo() {
return (
<RadioGroup defaultValue="standard" className="gap-3">
<div className="flex items-center gap-3">
<RadioGroupItem value="standard" id="ship-standard" />
<Label htmlFor="ship-standard">Standard shipping</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="express" id="ship-express" />
<Label htmlFor="ship-express">Express shipping</Label>
</div>
<div className="flex items-center gap-3" data-disabled>
<RadioGroupItem value="overnight" id="ship-overnight" disabled />
<Label htmlFor="ship-overnight">Overnight (unavailable)</Label>
</div>
</RadioGroup>
)
}Accessibility
Built on Radix Radio Group, following the WAI-ARIA radiogroup pattern.
- Arrow keys move between and select options; only one item is checked at a time.
- The group is reachable with Tab; focus lands on the checked item (or the first item if none is selected).
- Pair each
RadioGroupItemwith aLabelvia matchingid/htmlForso the hit target and screen-reader name are correct.