Radio group
@gridui/radio-group owns RadioGroup, Radio, and RadioCard as one
single-selection family. Import from the package root and load
@gridui/radio-group/styles.css after @gridui/theme/styles.css.
React and React DOM 19.2 or later are required, matching the shared Form
lifecycle contract. The package does not depend on application layout.
Selection and forms
RadioGroup retains string value / onValueChange for controlled state and
defaultValue for local state. onValueChange(value, details) receives the native
details.event; details.cancel() prevents an uncontrolled selection update.
Controlled callers own their state and must not commit a canceled change.
Activating an already selected item does not emit a value change.
The shared event protocol comes from @gridui/interaction.
The group forwards name, form, required, disabled, orientation, loop, refs,
and native accessibility props. readOnly permits focus without changing the
selection. Items also respect disabled fieldsets. Native form reset restores the
initial uncontrolled value unless the reset event is canceled; controlled callers
reset their own state. Radix owns radio semantics, hidden form inputs, and keyboard
navigation. Provide an accessible group name independently of item labels.
import { Radio, RadioGroup } from "@gridui/radio-group";
<RadioGroup name="delivery" defaultValue="standard" aria-label="Delivery service">
<label><Radio value="standard" /> Standard delivery</label>
<label><Radio value="express" /> Express delivery</label>
</RadioGroup>
Use comfortable visible label hit areas for compact Radio controls. Radio
and RadioCard can coexist in one group and share the same selection context.
Rich choices
RadioCard adds a required label, optional description, optional decorative
leading node, and variant="outlined" | "plain" to RadioProps, excluding
asChild. The default is outlined. Cards remain native radio buttons, not links
or independently managed toggles. Selection, form ownership, and callbacks stay
on RadioGroup; cards do not own columns or a second selection model.
The label and description have separate generated associations. Explicit
aria-label or aria-labelledby overrides the generated name. Supplied
aria-describedby is combined with the description association. leading is
hidden from assistive technology and must be decorative. Keep every slot free of
nested links, buttons, and inputs; essential information belongs in the label or
description. All slots accept phrasing content. Native refs point to the radio
button, and caller click/focus handlers can prevent a selection request.
<RadioGroup defaultValue="standard" aria-label="Delivery service">
<RadioCard value="standard" label="Standard delivery"
description="Delivered in three to five working days." />
<RadioCard value="express" label="Express delivery"
description="Delivered on the next working day." />
</RadioGroup>
Shared grid boundaries
The outlined variant owns its functional border. The plain variant adds no outer
border declarations, so GridItem asChild retains its structural seams. It does
not apply border: 0, inspect Grid internals, or infer an enclosing layout.
Both variants retain the themed background so a grid seam surface does not show
through the card body.
RadioGroup asChild delegates layout to its child without imposing the group's
default vertical flex arrangement. Grid remains responsible for responsive tracks,
shared boundaries, and optional cell padding.
Standalone cards default to spacing token 16. When composed with GridItem asChild,
the GridItem's padding takes precedence, including zero and responsive values,
regardless of the Grid and Radio-group stylesheet order. Caller spacing utilities
can override either value. RadioCard does not depend on Grid to apply this default.
import { Grid, GridItem } from "@gridui/grid";
import { RadioCard, RadioGroup } from "@gridui/radio-group";
<RadioGroup asChild defaultValue="standard" aria-label="Delivery service">
<Grid columns={{ base: 1, md: 2 }} frame="cells">
<GridItem asChild padding={16}>
<RadioCard value="standard" variant="plain" label="Standard"
description="Three to five working days." />
</GridItem>
<GridItem asChild padding={16}>
<RadioCard value="express" variant="plain" label="Express"
description="Next working day." />
</GridItem>
</Grid>
</RadioGroup>
Migration
Import Radio, RadioGroup, and their prop types from @gridui/radio-group
instead of @gridui/controls, and load the new stylesheet. Controls no longer
contains or re-exports this family. Existing values, callbacks, refs, forms,
read-only behavior, and keyboard contracts remain available.