apps/eclipse/content/design-system/components/radio-group.mdx
import { RadioGroup, RadioGroupItem, Field, FieldLabel, FieldDescription, FieldError } from "@prisma/eclipse";
Basic Radio Group
import { RadioGroup, RadioGroupItem } from "@prisma/eclipse";
export function BasicRadioGroup() {
return (
<RadioGroup defaultValue="option-one">
<div className="flex items-center gap-2">
<RadioGroupItem value="option-one" id="option-one" />
<label htmlFor="option-one" className="text-sm font-medium">Option One</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="option-two" id="option-two" />
<label htmlFor="option-two" className="text-sm font-medium">Option Two</label>
</div>
</RadioGroup>
);
}
Live Example:
<div className="my-4"> <RadioGroup defaultValue="option-one"> <div className="flex items-center gap-2"> <RadioGroupItem value="option-one" id="option-one-basic" /> <label htmlFor="option-one-basic" className="text-sm font-medium">Option One</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="option-two" id="option-two-basic" /> <label htmlFor="option-two-basic" className="text-sm font-medium">Option Two</label> </div> </RadioGroup> </div>With Descriptions
import { RadioGroup, RadioGroupItem } from "@prisma/eclipse";
export function RadioGroupWithDescriptions() {
return (
<RadioGroup defaultValue="comfortable">
<div className="flex items-center gap-2">
<RadioGroupItem value="default" id="default" />
<div className="flex flex-col gap-1">
<label htmlFor="default" className="text-sm font-medium">Default</label>
<span className="text-sm text-foreground-neutral-weak">The standard option for most users.</span>
</div>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="comfortable" id="comfortable" />
<div className="flex flex-col gap-1">
<label htmlFor="comfortable" className="text-sm font-medium">Comfortable</label>
<span className="text-sm text-foreground-neutral-weak">More spacing for better readability.</span>
</div>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="compact" id="compact" />
<div className="flex flex-col gap-1">
<label htmlFor="compact" className="text-sm font-medium">Compact</label>
<span className="text-sm text-foreground-neutral-weak">Minimal spacing to fit more content.</span>
</div>
</div>
</RadioGroup>
);
}
Live Example:
<div className="my-4"> <RadioGroup defaultValue="comfortable"> <div className="flex gap-2"> <RadioGroupItem value="default" id="default-desc" className="mt-0.5" /> <div className="flex flex-col gap-1"> <label htmlFor="default-desc" className="text-sm font-medium">Default</label> <span className="text-sm text-foreground-neutral-weak">The standard option for most users.</span> </div> </div> <div className="flex gap-2"> <RadioGroupItem value="comfortable" id="comfortable-desc" className="mt-0.5" /> <div className="flex flex-col gap-1"> <label htmlFor="comfortable-desc" className="text-sm font-medium">Comfortable</label> <span className="text-sm text-foreground-neutral-weak">More spacing for better readability.</span> </div> </div> <div className="flex gap-2"> <RadioGroupItem value="compact" id="compact-desc" className="mt-0.5" /> <div className="flex flex-col gap-1"> <label htmlFor="compact-desc" className="text-sm font-medium">Compact</label> <span className="text-sm text-foreground-neutral-weak">Minimal spacing to fit more content.</span> </div> </div> </RadioGroup> </div>With Field Component
import { RadioGroup, RadioGroupItem, Field, FieldLabel, FieldDescription } from "@prisma/eclipse";
export function RadioGroupWithField() {
return (
<Field>
<FieldLabel>Notification Frequency</FieldLabel>
<FieldDescription>Choose how often you want to receive notifications.</FieldDescription>
<RadioGroup defaultValue="daily">
<div className="flex items-center gap-2">
<RadioGroupItem value="realtime" id="realtime" />
<label htmlFor="realtime" className="text-sm font-medium">Real-time</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="daily" id="daily" />
<label htmlFor="daily" className="text-sm font-medium">Daily digest</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="weekly" id="weekly" />
<label htmlFor="weekly" className="text-sm font-medium">Weekly summary</label>
</div>
</RadioGroup>
</Field>
);
}
Live Example:
<div className="max-w-md my-4"> <Field> <FieldLabel>Notification Frequency</FieldLabel> <FieldDescription>Choose how often you want to receive notifications.</FieldDescription> <RadioGroup defaultValue="daily"> <div className="flex items-center gap-2"> <RadioGroupItem value="realtime" id="realtime-field" /> <label htmlFor="realtime-field" className="text-sm font-medium">Real-time</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="daily" id="daily-field" /> <label htmlFor="daily-field" className="text-sm font-medium">Daily digest</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="weekly" id="weekly-field" /> <label htmlFor="weekly-field" className="text-sm font-medium">Weekly summary</label> </div> </RadioGroup> </Field> </div>Controlled Radio Group
import { RadioGroup, RadioGroupItem } from "@prisma/eclipse";
import { useState } from "react";
export function ControlledRadioGroup() {
const [value, setValue] = useState("option-one");
return (
<div className="space-y-4">
<RadioGroup value={value} onValueChange={setValue}>
<div className="flex items-center gap-2">
<RadioGroupItem value="option-one" id="controlled-one" />
<label htmlFor="controlled-one" className="text-sm font-medium">Option One</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="option-two" id="controlled-two" />
<label htmlFor="controlled-two" className="text-sm font-medium">Option Two</label>
</div>
</RadioGroup>
<span className="text-sm text-foreground-neutral-weak">
Selected: {value}
</span>
</div>
);
}
Live Example:
<div className="space-y-4 my-4"> <RadioGroup defaultValue="option-one"> <div className="flex items-center gap-2"> <RadioGroupItem value="option-one" id="controlled-one-example" /> <label htmlFor="controlled-one-example" className="text-sm font-medium">Option One</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="option-two" id="controlled-two-example" /> <label htmlFor="controlled-two-example" className="text-sm font-medium">Option Two</label> </div> </RadioGroup> </div>Disabled State
import { RadioGroup, RadioGroupItem } from "@prisma/eclipse";
export function DisabledRadioGroup() {
return (
<RadioGroup defaultValue="option-one">
<div className="flex items-center gap-2">
<RadioGroupItem value="option-one" id="disabled-one" disabled />
<label htmlFor="disabled-one" className="text-sm font-medium opacity-70 cursor-not-allowed">Disabled option (selected)</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="option-two" id="disabled-two" disabled />
<label htmlFor="disabled-two" className="text-sm font-medium opacity-70 cursor-not-allowed">Disabled option</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="option-three" id="enabled-three" />
<label htmlFor="enabled-three" className="text-sm font-medium">Enabled option</label>
</div>
</RadioGroup>
);
}
Live Example:
<div className="my-4"> <RadioGroup defaultValue="option-one"> <div className="flex items-center gap-2"> <RadioGroupItem value="option-one" id="disabled-one-example" disabled /> <label htmlFor="disabled-one-example" className="text-sm font-medium opacity-70 cursor-not-allowed">Disabled option (selected)</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="option-two" id="disabled-two-example" disabled /> <label htmlFor="disabled-two-example" className="text-sm font-medium opacity-70 cursor-not-allowed">Disabled option</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="option-three" id="enabled-three-example" /> <label htmlFor="enabled-three-example" className="text-sm font-medium">Enabled option</label> </div> </RadioGroup> </div>Horizontal Layout
import { RadioGroup, RadioGroupItem } from "@prisma/eclipse";
export function HorizontalRadioGroup() {
return (
<RadioGroup defaultValue="small" className="flex gap-4">
<div className="flex items-center gap-2">
<RadioGroupItem value="small" id="size-small" />
<label htmlFor="size-small" className="text-sm font-medium">Small</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="medium" id="size-medium" />
<label htmlFor="size-medium" className="text-sm font-medium">Medium</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="large" id="size-large" />
<label htmlFor="size-large" className="text-sm font-medium">Large</label>
</div>
</RadioGroup>
);
}
Live Example:
<div className="my-4"> <RadioGroup defaultValue="small" className="flex gap-4"> <div className="flex items-center gap-2"> <RadioGroupItem value="small" id="size-small-horizontal" /> <label htmlFor="size-small-horizontal" className="text-sm font-medium">Small</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="medium" id="size-medium-horizontal" /> <label htmlFor="size-medium-horizontal" className="text-sm font-medium">Medium</label> </div> <div className="flex items-center gap-2"> <RadioGroupItem value="large" id="size-large-horizontal" /> <label htmlFor="size-large-horizontal" className="text-sm font-medium">Large</label> </div> </RadioGroup> </div>In Forms
import { RadioGroup, RadioGroupItem, Button } from "@prisma/eclipse";
export function RadioGroupForm() {
return (
<form className="space-y-6 max-w-md">
<div className="space-y-4">
<h3 className="text-lg font-semibold">Shipping Method</h3>
<RadioGroup defaultValue="standard" name="shipping">
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="standard" id="standard-shipping" />
<div className="flex flex-col gap-1">
<label htmlFor="standard-shipping" className="text-sm font-medium">Standard Shipping</label>
<span className="text-sm text-foreground-neutral-weak">5-7 business days</span>
</div>
</div>
<span className="text-sm font-medium">Free</span>
</div>
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="express" id="express-shipping" />
<div className="flex flex-col gap-1">
<label htmlFor="express-shipping" className="text-sm font-medium">Express Shipping</label>
<span className="text-sm text-foreground-neutral-weak">2-3 business days</span>
</div>
</div>
<span className="text-sm font-medium">$15.00</span>
</div>
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="overnight" id="overnight-shipping" />
<div className="flex flex-col gap-1">
<label htmlFor="overnight-shipping" className="text-sm font-medium">Overnight Shipping</label>
<span className="text-sm text-foreground-neutral-weak">Next business day</span>
</div>
</div>
<span className="text-sm font-medium">$30.00</span>
</div>
</RadioGroup>
</div>
<Button type="submit">Continue to payment</Button>
</form>
);
}
Live Example:
<form className="space-y-6 max-w-md my-4"> <div className="space-y-4"> <h3 className="text-lg font-semibold">Shipping Method</h3><RadioGroup defaultValue="standard" name="shipping">
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="standard" id="standard-shipping-form" />
<div className="flex flex-col gap-1">
<label htmlFor="standard-shipping-form" className="text-sm font-medium">Standard Shipping</label>
<span className="text-sm text-foreground-neutral-weak">5-7 business days</span>
</div>
</div>
<span className="text-sm font-medium">Free</span>
</div>
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="express" id="express-shipping-form" />
<div className="flex flex-col gap-1">
<label htmlFor="express-shipping-form" className="text-sm font-medium">Express Shipping</label>
<span className="text-sm text-foreground-neutral-weak">2-3 business days</span>
</div>
</div>
<span className="text-sm font-medium">$15.00</span>
</div>
<div className="flex items-center justify-between p-4 border rounded-lg">
<div className="flex items-center gap-3">
<RadioGroupItem value="overnight" id="overnight-shipping-form" />
<div className="flex flex-col gap-1">
<label htmlFor="overnight-shipping-form" className="text-sm font-medium">Overnight Shipping</label>
<span className="text-sm text-foreground-neutral-weak">Next business day</span>
</div>
</div>
<span className="text-sm font-medium">$30.00</span>
</div>
</RadioGroup>
RadioGroup
value - Controlled value (string, optional)defaultValue - Default value for uncontrolled usage (string, optional)onValueChange - Callback when value changes (function, optional)disabled - Whether the group is disabled (boolean, default: false)required - Whether selection is required (boolean, default: false)name - Name for form submission (string, optional)className - Additional CSS classes (string, optional)RadioGroupItem
value - Value of this radio item (string, required)disabled - Whether this item is disabled (boolean, default: false)id - HTML id attribute (string, optional)className - Additional CSS classes (string, optional)htmlFor on labels to match RadioGroupItem iddefaultValue for uncontrolled usageThe RadioGroup component is perfect for:
The RadioGroup component follows accessibility best practices:
role="radiogroup", aria-checked)The RadioGroup component uses design tokens:
border-primaryfill-primaryring-ringrounded-fullgap-2 (8px between items)Customize by passing className:
<RadioGroup className="flex gap-4">
<RadioGroupItem className="border-2 border-blue-500" />
</RadioGroup>
RadioGroup works well with:
The RadioGroup component works seamlessly with forms:
<form onSubmit={handleSubmit}>
<RadioGroup name="plan" defaultValue="pro" required>
<RadioGroupItem value="free" id="free" />
<RadioGroupItem value="pro" id="pro" />
</RadioGroup>
<button type="submit">Submit</button>
</form>
When selected, the form data will include the selected value with the specified name.