radio
Custom-styled radio buttons with full keyboard and screen-reader support. Use radio() for a single option or radioGroup() for a semantic group inside a form.
Radio group
The standard usage. radioGroup() renders a <fieldset> with a <legend> and marks the currently selected option via the value prop.
radioGroup({
name: 'plan',
legend: 'Plan',
value: state.plan, // marks the selected option
options: [
{ value: 'starter', label: 'Starter' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
],
})Per-option hints
Each option accepts a hint string for supporting copy below the label.
radioGroup({
name: 'billing',
legend: 'Billing cycle',
value: state.billing,
options: [
{ value: 'monthly', label: 'Monthly', hint: 'Billed every month. Cancel any time.' },
{ value: 'annual', label: 'Annual', hint: 'Billed once a year. Save 20%.' },
],
})Error state
Pass error to show a validation message below the group. The message is linked via aria-describedby.
radioGroup({
name: 'size',
legend: 'Size',
error: server.errors.size,
options: [
{ value: 'sm', label: 'Small' },
{ value: 'md', label: 'Medium' },
{ value: 'lg', label: 'Large' },
],
})Disabled options
Set disabled: true on individual options, or pass disabled at the group level to disable all.
radioGroup({
name: 'tier',
legend: 'Tier',
value: state.tier,
options: [
{ value: 'basic', label: 'Basic' },
{ value: 'pro', label: 'Pro' },
{ value: 'enterprise', label: 'Enterprise', disabled: true },
],
})Gap
Control spacing between options with gap: 'sm' · 'md' (default) · 'lg'.
radioGroup({ ..., gap: 'lg' })Single radio
Use radio() directly when you need to compose your own group layout — for example inside a fieldset alongside other controls.
fieldset({
legend: 'Preferred contact',
content:
radio({ name: 'contact', value: 'email', label: 'Email', checked: true }) +
radio({ name: 'contact', value: 'phone', label: 'Phone' }),
})In forms
Radio groups submit the selected
value string under name in FormData. If nothing is selected, the field is absent from FormData. Read it in action.onStart or action.run via formData.get('plan').radioGroup() props
| Prop | Type | Default | |
|---|---|---|---|
name | string | — | Shared name attribute for all inputs in the group |
legend | string | — | Group label — renders as a <legend> |
options | array | [] | Array of { value, label, hint?, disabled? } |
value | string | — | The currently selected value — marks the matching option as checked |
hint | string | — | Helper text below the group |
error | string | — | Validation error — linked via aria-describedby |
gap | sm | md | lg | md | Spacing between options |
class | string | — |
radio() props
| Prop | Type | Default | |
|---|---|---|---|
name | string | — | Field name |
value | string | — | Submitted value when this option is selected |
label | string | — | Visible label |
checked | boolean | false | |
disabled | boolean | false | |
id | string | — | Override the generated id |
class | string | — |