Radio Group
A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
RadioGroup wraps Kobalte's Radio Group primitive, which implements the WAI-ARIA radio group pattern with roving-tabindex keyboard navigation and native form participation.
import { Label } from "~/components/ui/label";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupDemo() { return ( <RadioGroup defaultValue="comfortable" class="w-fit"> <div class="flex items-center gap-3"> <RadioGroupItem value="default" id="radio-group-demo-default" /> <Label for="radio-group-demo-default">Default</Label> </div> <div class="flex items-center gap-3"> <RadioGroupItem value="comfortable" id="radio-group-demo-comfortable" /> <Label for="radio-group-demo-comfortable">Comfortable</Label> </div> <div class="flex items-center gap-3"> <RadioGroupItem value="compact" id="radio-group-demo-compact" /> <Label for="radio-group-demo-compact">Compact</Label> </div> </RadioGroup> );}Installation
Usage
import { Label } from "~/components/ui/label";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";<RadioGroup defaultValue="option-one"> <div class="flex items-center gap-3"> <RadioGroupItem value="option-one" id="option-one" /> <Label for="option-one">Option One</Label> </div> <div class="flex items-center gap-3"> <RadioGroupItem value="option-two" id="option-two" /> <Label for="option-two">Option Two</Label> </div></RadioGroup>Composition
Use the following composition to build a RadioGroup:
RadioGroup├── RadioGroupItem└── RadioGroupItemDescription
Radio group items with a description using the Field component.
Standard spacing for most use cases.
More space between elements.
Minimal spacing for dense layouts.
import { Field, FieldContent, FieldDescription, FieldLabel } from "~/components/ui/field";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupDescription() { return ( <RadioGroup defaultValue="comfortable" class="w-fit"> <Field orientation="horizontal"> <RadioGroupItem value="default" id="radio-group-description-default" /> <FieldContent> <FieldLabel for="radio-group-description-default">Default</FieldLabel> <FieldDescription>Standard spacing for most use cases.</FieldDescription> </FieldContent> </Field> <Field orientation="horizontal"> <RadioGroupItem value="comfortable" id="radio-group-description-comfortable" /> <FieldContent> <FieldLabel for="radio-group-description-comfortable">Comfortable</FieldLabel> <FieldDescription>More space between elements.</FieldDescription> </FieldContent> </Field> <Field orientation="horizontal"> <RadioGroupItem value="compact" id="radio-group-description-compact" /> <FieldContent> <FieldLabel for="radio-group-description-compact">Compact</FieldLabel> <FieldDescription>Minimal spacing for dense layouts.</FieldDescription> </FieldContent> </Field> </RadioGroup> );}Choice Card
Use FieldLabel to wrap the entire Field for a clickable card-style selection.
import { Field, FieldContent, FieldDescription, FieldLabel, FieldTitle,} from "~/components/ui/field";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupChoiceCard() { return ( <RadioGroup defaultValue="plus" class="max-w-sm"> <FieldLabel for="radio-group-plan-plus"> <Field orientation="horizontal"> <FieldContent> <FieldTitle>Plus</FieldTitle> <FieldDescription>For individuals and small teams.</FieldDescription> </FieldContent> <RadioGroupItem value="plus" id="radio-group-plan-plus" /> </Field> </FieldLabel> <FieldLabel for="radio-group-plan-pro"> <Field orientation="horizontal"> <FieldContent> <FieldTitle>Pro</FieldTitle> <FieldDescription>For growing businesses.</FieldDescription> </FieldContent> <RadioGroupItem value="pro" id="radio-group-plan-pro" /> </Field> </FieldLabel> <FieldLabel for="radio-group-plan-enterprise"> <Field orientation="horizontal"> <FieldContent> <FieldTitle>Enterprise</FieldTitle> <FieldDescription>For large teams and enterprises.</FieldDescription> </FieldContent> <RadioGroupItem value="enterprise" id="radio-group-plan-enterprise" /> </Field> </FieldLabel> </RadioGroup> );}Fieldset
Use FieldSet and FieldLegend to group radio items with a label and description.
import { Field, FieldDescription, FieldLabel, FieldLegend, FieldSet,} from "~/components/ui/field";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupFieldset() { return ( <FieldSet class="w-full max-w-xs"> <FieldLegend variant="label">Subscription Plan</FieldLegend> <FieldDescription>Yearly and lifetime plans offer significant savings.</FieldDescription> <RadioGroup defaultValue="monthly"> <Field orientation="horizontal"> <RadioGroupItem value="monthly" id="radio-group-plan-monthly" /> <FieldLabel for="radio-group-plan-monthly" class="font-normal"> Monthly ($9.99/month) </FieldLabel> </Field> <Field orientation="horizontal"> <RadioGroupItem value="yearly" id="radio-group-plan-yearly" /> <FieldLabel for="radio-group-plan-yearly" class="font-normal"> Yearly ($99.99/year) </FieldLabel> </Field> <Field orientation="horizontal"> <RadioGroupItem value="lifetime" id="radio-group-plan-lifetime" /> <FieldLabel for="radio-group-plan-lifetime" class="font-normal"> Lifetime ($299.99) </FieldLabel> </Field> </RadioGroup> </FieldSet> );}Disabled
Use the disabled prop on RadioGroup to disable all items, or on RadioGroupItem to disable an individual item.
import { Field, FieldLabel } from "~/components/ui/field";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupDisabled() { return ( <RadioGroup defaultValue="option2" class="w-fit"> <Field orientation="horizontal" data-disabled> <RadioGroupItem value="option1" id="radio-group-disabled-1" disabled /> <FieldLabel for="radio-group-disabled-1" class="font-normal"> Disabled </FieldLabel> </Field> <Field orientation="horizontal"> <RadioGroupItem value="option2" id="radio-group-disabled-2" /> <FieldLabel for="radio-group-disabled-2" class="font-normal"> Option 2 </FieldLabel> </Field> <Field orientation="horizontal"> <RadioGroupItem value="option3" id="radio-group-disabled-3" /> <FieldLabel for="radio-group-disabled-3" class="font-normal"> Option 3 </FieldLabel> </Field> </RadioGroup> );}Invalid
Use aria-invalid on RadioGroupItem and data-invalid on Field to show validation errors.
import { Field, FieldDescription, FieldLabel, FieldLegend, FieldSet,} from "~/components/ui/field";import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
export default function RadioGroupInvalid() { return ( <FieldSet class="w-full max-w-xs"> <FieldLegend variant="label">Notification Preferences</FieldLegend> <FieldDescription>Choose how you want to receive notifications.</FieldDescription> <RadioGroup defaultValue="email"> <Field orientation="horizontal" data-invalid> <RadioGroupItem value="email" id="radio-group-invalid-email" aria-invalid /> <FieldLabel for="radio-group-invalid-email" class="font-normal"> Email only </FieldLabel> </Field> <Field orientation="horizontal" data-invalid> <RadioGroupItem value="sms" id="radio-group-invalid-sms" aria-invalid /> <FieldLabel for="radio-group-invalid-sms" class="font-normal"> SMS only </FieldLabel> </Field> <Field orientation="horizontal" data-invalid> <RadioGroupItem value="both" id="radio-group-invalid-both" aria-invalid /> <FieldLabel for="radio-group-invalid-both" class="font-normal"> Both Email & SMS </FieldLabel> </Field> </RadioGroup> </FieldSet> );}API Reference
RadioGroup and RadioGroupItem wrap Kobalte's Radio Group primitive, which implements the WAI-ARIA radio group pattern, including roving-tabindex keyboard navigation, disabled, read-only, and form reset behavior.