RadioGroup

Selects one option from a mutually exclusive set.

import { RadioGroup } from "@usefragments/ui";Source

Preview

<RadioGroup defaultValue="option1" label="Select an option">
  <RadioGroup.Item value="option1" label="Option 1" />
  <RadioGroup.Item value="option2" label="Option 2" />
  <RadioGroup.Item value="option3" label="Option 3" />
</RadioGroup>

Usage

Use when

  • Exactly one answer out of two to five
  • Options rule each other out
  • Every option should be visible without opening anything

Avoid when

  • Several answers allowed (use a Checkbox group)
  • Long lists (use Select)
  • A single on/off (use Switch)
  • Options need searching (use Combobox)

Implementation notes

  • Pre-select a sensible default whenever one exists
  • Order options predictably: alphabetical, by frequency, or by cost
  • Keep labels short
  • Put the trade-off in each item's helperText

Installation

pnpm add @usefragments/ui

The npm package stays managed by your package manager. Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Anatomy

Import RadioGroup once, then compose its parts with dot notation.

  • RadioGroup.Item

Three options stacked, the first already chosen.

<RadioGroup defaultValue="option1" label="Select an option">
  <RadioGroup.Item value="option1" label="Option 1" />
  <RadioGroup.Item value="option2" label="Option 2" />
  <RadioGroup.Item value="option3" label="Option 3" />
</RadioGroup>

Examples

With Helper Text

Each option carries the trade-off under its label.

<RadioGroup defaultValue="standard" label="Shipping Method">
  <RadioGroup.Item
    value="standard"
    label="Standard"
    helperText="5-7 business days"
  />

Horizontal

One row — good for short labels like sizes.

<RadioGroup orientation="horizontal" defaultValue="small" label="Size">
  <RadioGroup.Item value="small" label="S" />
  <RadioGroup.Item value="medium" label="M" />
  <RadioGroup.Item value="large" label="L" />
  <RadioGroup.Item value="xlarge" label="XL" />
</RadioGroup>

With Group Helper Text

One note under the whole group instead of per option.

<RadioGroup defaultValue="standard" label="Plan" helperText="You can change your plan at any time">
  <RadioGroup.Item value="free" label="Free" />
  <RadioGroup.Item value="standard" label="Standard" />
  <RadioGroup.Item value="pro" label="Pro" />
</RadioGroup>

With Error

invalid draws the danger edge on every circle; errorMessage prints the reason with an icon.

<RadioGroup
  label="Required selection"
  invalid
  errorMessage="Choose an option to continue."
>
  <RadioGroup.Item value="a" label="Option A" />

Disabled

The choice stays visible but nothing can change it.

<RadioGroup disabled defaultValue="locked" label="Locked selection">
  <RadioGroup.Item value="locked" label="This is locked" />
  <RadioGroup.Item value="other" label="Cannot select" />
</RadioGroup>

API reference

Component props
Prop
Type
Default
Description
childrenRequiredReact.ReactNodeNot setRadioGroup.Item elements
defaultValuestring | undefinedNot setDefault value (uncontrolled)
disabledboolean | undefinedfalseDisable every option; the group dims once
errorMessageReact.ReactNodeNot setMessage shown with a warning icon under the group while invalid; wired to the radiogroup's aria-describedby
formstring | undefinedNot setID of the form that owns the radio inputs
helperTextstring | undefinedNot setHelper text shown below the group
inputRefReact.Ref<HTMLInputElement> | undefinedNot setRef to the hidden input element
invalidboolean | undefinedfalseThe value fails validation: every circle takes the danger edge and errorMessage shows under the group
Item.aria-describedbystring | undefinedNot setAccessible described-by relationship
Item.aria-labelstring | undefinedNot setAccessible name when there is no visible label
Item.aria-labelledbystring | undefinedNot setAccessible labelled-by relationship
Item.classNamestring | undefinedNot setAdditional class name
Item.disabledboolean | undefinedNot setWhether this item is disabled
Item.helperTextstring | undefinedNot setHelper text shown below the label
Item.labelstring | undefinedNot setLabel text
Item.trailingReact.ReactNodeNot setA value at the end of the row, on the label's line: a price, a count, a date. Read by the label's accessible name, so keep it short and put the explanation in `helperText`.
Item.valueRequiredstringNot setThe value for this radio item
labelstring | undefinedNot setGroup label
namestring | undefinedNot setForm field name
onValueChange((value: string) => void) | undefinedNot setCallback when selection changes
orientation"horizontal" | "vertical" | undefinedhorizontalverticalverticalLayout orientation
readOnlyboolean | undefinedfalseThe chosen option cannot be changed; item rows stop hovering
requiredboolean | undefinedfalseA value must be chosen before the form submits
valuestring | undefinedNot setControlled selected value
variant"outline" | undefinedoutlineNot setChrome. Omit for the inline radio beside its label; 'outline' renders each item as a full-width choice card (surface, hairline, surface radius) whose hairline turns into the selection ring when chosen.
idstring | undefinedNot setID for the element with role=radiogroup (the ref lands there too)

Accessibility

  • The group carries its own label
  • Arrow keys move between options
  • The selected option reads as checked
  • CheckboxalternativeUse Checkbox for multiple selections
  • SelectalternativeUse Select for many options or limited space
  • SwitchalternativeUse Switch for binary on/off choices

Next steps