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 — for example inside a fieldset alongside other controls.

Preferred contact
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

PropTypeDefault
namestringShared name attribute for all inputs in the group
legendstringGroup label — renders as a <legend>
optionsarray[]Array of { value, label, hint?, disabled? }
valuestringThe currently selected value — marks the matching option as checked
hintstringHelper text below the group
errorstringValidation error — linked via aria-describedby
gapsm | md | lgmdSpacing between options
classstring

radio() props

PropTypeDefault
namestringField name
valuestringSubmitted value when this option is selected
labelstringVisible label
checkedbooleanfalse
disabledbooleanfalse
idstringOverride the generated id
classstring