7.1 KiB
RadioGroup
(no submodules)
- radio-group.variants — `radioGroupVariants` and `ra…-
radio-group.variants —
radioGroupVariantsandradioGroupItemVariantsare the cva (class-variance-authority) configurations powering `<Radi… -
radio-group.variants —
radioGroupVariantsand `ra… -
radio-group.variants —
radioGroupVariantsandradioGroupItemVariantsare the cva (class-variance-authority) configurations powering `<Radi… -
radio-group.variants —
radioGroupVariantsand `ra… -
radio-group.variants —
radioGroupVariantsandradioGroupItemVariantsare the cva (class-variance-authority) configurations powering `<Radi… -
radio-group.variants —
radioGroupVariantsand `ra… -
radio-group.variants —
radioGroupVariantsandradioGroupItemVariantsare the cva (class-variance-authority) configurations powering `<Radi… -
radio-group.variants —
radioGroupVariantsandradioGroupItemVariantsare the cva (class-variance-authority) configurations powering `<Radi…
Purpose
<RadioGroup> and <RadioGroupItem> are the chassis radio-group primitives built on @radix-ui/react-radio-group. Radix supplies the a11y semantics (role="radiogroup" on the container, role="radio" on each item, roving tabindex across items, arrow-key navigation, native Space activation, controlled value propagation); the chassis layers a vertical-stack flex/gap layout via cva and a circular indicator dot rendered with <CircleIcon fill-current> from lucide-react.
Per the shadcn convention, items always sit inside the group via <RadioGroupItem> — rendering an item without a group is unsupported. Both components forward refs to their underlying Radix elements so consumers can focus / measure / drive animations.
Features
- Container renders a
<div role="radiogroup">withgrid gap-2so items stack vertically with a small uniform gap (NOTspace-y-*per the shadcn skill rule). - Items render a
<button role="radio">with the circularborder-primaryoutline. - Three sizes for items (
sm,default,lg) scaling the radio circle. - Indicator dot rendered via
<CircleIcon fill-current text-current>so the dot inherits the surrounding text colour and the chassis switches it without an extra theme prop. - Controlled and uncontrolled use via Radix
value/defaultValue/onValueChange. disabledper-item or per-group blocks pointer + keyboard input.- Refs forwarded on both
<RadioGroup>and<RadioGroupItem>. motion-reduce:transition-nonecollapses transitions forprefers-reduced-motion: reduce.- Theme-driven variant overrides via
useThemedVariants("RadioGroup" | "RadioGroupItem").
Usage: Basic Example
import { RadioGroup, RadioGroupItem } from "@suaveplan/react-ui";
export function PlanPicker() {
return (
<RadioGroup defaultValue="pro">
<div className="flex items-center gap-2">
<RadioGroupItem value="free" id="plan-free" />
<label htmlFor="plan-free">Free</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="pro" id="plan-pro" />
<label htmlFor="plan-pro">Pro</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="team" id="plan-team" />
<label htmlFor="plan-team">Team</label>
</div>
</RadioGroup>
);
}
Usage: Advanced Example
import { RadioGroup, RadioGroupItem, FieldSet, FieldLegend } from "@suaveplan/react-ui";
import { useState } from "react";
interface DeliverySpeed {
readonly id: string;
readonly label: string;
readonly description: string;
readonly disabled?: boolean;
}
export function DeliveryPicker({ options }: { options: readonly DeliverySpeed[] }) {
const [speed, setSpeed] = useState("standard");
return (
<FieldSet>
<FieldLegend>Delivery speed</FieldLegend>
<RadioGroup value={speed} onValueChange={setSpeed}>
{options.map((opt) => (
<div key={opt.id} className="flex items-start gap-2">
<RadioGroupItem
value={opt.id}
id={`delivery-${opt.id}`}
disabled={opt.disabled}
className="mt-1"
/>
<div>
<label htmlFor={`delivery-${opt.id}`}>{opt.label}</label>
<p className="text-sm text-muted-foreground">
{opt.description}
</p>
</div>
</div>
))}
</RadioGroup>
</FieldSet>
);
}
API Reference
<RadioGroup>
forwardRef<ComponentRef<typeof RadioGroupPrimitive.Root>, RadioGroupProps> — renders the Radix Root.
RadioGroupProps
Inherits every prop from Radix RadioGroupPrimitive.Root except asChild. Common props:
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
uncontrolled | Currently selected value. |
defaultValue |
string |
none | Initial value for uncontrolled use. |
onValueChange |
(value: string) => void |
none | Fires on value change. |
disabled |
boolean |
false |
Disables every item. |
name |
string |
none | Native form-field name. |
orientation |
"horizontal" | "vertical" |
"vertical" |
Arrow-key navigation axis. |
<RadioGroupItem>
forwardRef<ComponentRef<typeof RadioGroupPrimitive.Item>, RadioGroupItemProps> — renders a Radix Item containing the indicator dot.
RadioGroupItemProps
Inherits every prop from Radix RadioGroupPrimitive.Item except asChild. Adds:
| Prop | Type | Default | Description |
|---|---|---|---|
size |
"sm" | "default" | "lg" |
"default" |
Visual variant scaling the radio circle. |
value |
string |
required | Unique value within the surrounding group. |
radioGroupVariants / radioGroupItemVariants
Both bare cva resolvers exported for external composition.
Implementation Notes
- The container uses
grid gap-2rather thanflex flex-col gap-2becausegridcollapses cross-axis layout in a way that keeps the items column-aligned even when they have wildly different content lengths (label + description blocks). - Per the shadcn skill rule, the chassis NEVER uses
space-y-*—grid gap-*flows the same in RTL. - The indicator dot uses
fill-current text-currentso it inherits the surrounding text colour automatically; theme overrides do not need to special-case the dot. - Refs target the Radix Root + Item. The Item ref attaches to the rendered
<button>so consumers can.focus()programmatically. - Items that require a description/help text typically wrap the radio + content in
<div className="flex items-start gap-2">withmt-1on the radio so the dot aligns with the first line of text.