GitHub

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.

Plan
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.

Billing cycle

Billed every month. Cancel any time.

Billed once a year. Save 20%.

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.

Size
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.

Tier
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'.

Colour
radioGroup({ ..., gap: 'lg' })

Single radio

Use radio() directly when you need to compose your own group layout.

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

PropTypeDefaultDescription
namestring—Shared name attribute for all inputs in the group
legendstring—Group label — renders as a <legend>
optionsarray[]Array of { value, label, hint?, disabled? }
valuestring—The currently selected value — marks the matching option as checked
hintstring—Helper text below the group
errorstring—Validation error — linked via aria-describedby
gapsm | md | lgmdSpacing between options
classstring—

radio() props

PropTypeDefaultDescription
namestring—Field name
valuestring—Submitted value when this option is selected
labelstring—Visible label
checkedbooleanfalse
disabledbooleanfalse
idstring—Override the generated id
classstring—