StackForm
Components

RadioGroupField

Radio button group for selecting a single option from a list

RadioGroupField renders a labeled, accessible <fieldset role="radiogroup"> connected to the active form adapter via context. Error and hint states surface automatically — no prop wiring needed.

Props

PropTypeRequiredDefaultDescription
namestringyesField name. Used as the form state key and to derive element IDs.
labelstringLabel text rendered as the fieldset legend.
hintstringHelper text shown below the options when no error is present.
optionsRadioOption<T>[]yesArray of radio options. Each option has a value, label, optional description, and optional disabled flag.
orientation'horizontal' | 'vertical''vertical'Layout direction of the radio group.
disabledbooleanfalseDisables all options. Inherits from StackFormProvider if not set.
loadingbooleanfalseReplaces the options with a skeleton shimmer.
requiredbooleanfalseMarks the field as required. Appends * to the label.
classNamesRadioGroupFieldClassNamesTailwind class overrides per slot. Stacks with provider and core classes.
slotsRadioGroupFieldSlotsComponent overrides per slot. First non-null wins: field → provider → default.
slotProps{ wrapper?, label?, error?, hint? }Extra props passed to each slot. Field-level replaces provider-level per key.
onValueChange(value: T) => voidCalled after onChange with the new value.
validate(value: T) => string | undefined | Promise<string | undefined>Field-level validator. Runs on blur.

RadioOption

Each item in the options array follows this interface:

interface RadioOption<T = string> {
  value: T
  label: string
  description?: string
  disabled?: boolean
}

Slots

SlotProp interfaceDescription
WrapperWrapperSlotPropsOuter container element
LabelLabelSlotPropsRenders as the fieldset <legend>. Note: the fieldset's aria-labelledby reference will be unresolved when this slot is used.
OptionRadioOptionSlotPropsIndividual radio option container
ErrorErrorSlotPropsError message
HintHintSlotPropsHint/helper text

classNames

KeyApplied to
wrapperOuter container
labelFieldset legend
input(Base class, unused in RadioGroupField)
errorError message
hintHint text
optionIndividual radio option wrapper
optionLabelRadio option label text
optionDescriptionRadio option description text
groupFieldset element

Examples

With error

Errors surface automatically from the form adapter. Trigger one manually to test:

form.setError('role', { message: 'Please select a role' })

<RadioGroupField
  name="role"
  label="Select your role"
  options={[
    { value: 'user', label: 'User' },
    { value: 'admin', label: 'Administrator' },
    { value: 'viewer', label: 'Viewer' },
  ]}
/>

With hint

<RadioGroupField
  name="newsletter"
  label="Newsletter preference"
  hint="Choose how often you'd like to receive updates."
  options={[
    { value: 'weekly', label: 'Weekly' },
    { value: 'monthly', label: 'Monthly' },
    { value: 'never', label: 'Never' },
  ]}
/>

Horizontal layout

<RadioGroupField
  name="size"
  label="Select size"
  orientation="horizontal"
  options={[
    { value: 'small', label: 'Small' },
    { value: 'medium', label: 'Medium' },
    { value: 'large', label: 'Large' },
  ]}
/>

With descriptions and a disabled option

<RadioGroupField
  name="plan"
  label="Choose a plan"
  options={[
    {
      value: 'basic',
      label: 'Basic',
      description: 'Perfect for getting started.',
    },
    {
      value: 'pro',
      label: 'Professional',
      description: 'For growing teams.',
    },
    {
      value: 'enterprise',
      label: 'Enterprise',
      description: 'Custom solutions available.',
      disabled: true,
    },
  ]}
/>

With slot override

Replace the Label slot with a custom component. Slot components receive only display-level props.

import type { LabelSlotProps } from '@stackform/ui'

function CustomLabel({ htmlFor, children, required }: LabelSlotProps) {
  return (
    <legend className="text-lg font-semibold text-blue-700">
      {children}
      {required ? <span aria-hidden="true"> *</span> : null}
    </legend>
  )
}

<RadioGroupField
  name="priority"
  label="Set priority"
  options={[
    { value: 'low', label: 'Low' },
    { value: 'medium', label: 'Medium' },
    { value: 'high', label: 'High' },
  ]}
  slots={{ Label: CustomLabel }}
/>