Skip to content

Design system

Documentation

DesignComponents / RadioGroup

Components / RadioGroup

Stable

RadioGroup

Use RadioGroup when a person must choose exactly one option from a short, mutually exclusive set.

On this page

Examples

One choice

A named group makes one mutually exclusive option easy to understand.

Choose one plan for this workspace.

RadioGroup with a label and description

Density

Use sm, md, or lg so the radio matches the surrounding form rhythm.

RadioGroup small, default, and large sizes

Vertical and horizontal

Choose the layout that matches the number and length of options.

Vertical and horizontal RadioGroup layouts

Controlled value

Feature state owns the selected value when it coordinates another view.

Controlled RadioGroup preview

Disabled and read-only

Unavailable options stay visible while the group keeps its selected value clear.

Disabled option and read-only RadioGroup

Native form value

A group submits one value through the native form contract.

RadioGroup with native form semantics

When to use

Use RadioGroup for a visible set of two or more alternatives where only one value is valid. Use Select when the list is long or space is limited, and Checkbox when choices are independent.

Usage

radio-group-basic.tsx
"use client";

import { Field, FieldDescription, FieldLabel } from "@phuctech/ui/components/field";
import { RadioGroup, RadioGroupItem } from "@phuctech/ui/components/radio-group";

const plans = ["Starter", "Growth", "Scale"] as const;

export function Example() {
  return (
    <Field>
      <FieldLabel>Plan</FieldLabel>
      <FieldDescription>Choose one plan for this workspace.</FieldDescription>
      <RadioGroup name="plan" defaultValue="Growth" aria-label="Plan">
        {plans.map((plan) => (
          <label key={plan} className="flex items-center gap-2 text-sm">
            <RadioGroupItem value={plan} />
            {plan}
          </label>
        ))}
      </RadioGroup>
    </Field>
  );
}

Give the group an accessible name with FieldLabel or aria-label, then give each item a visible label. The group owns the value; the feature owns what changing it means.

Behavior

  • Arrow keys move between radio items while Tab enters and leaves the group once.
  • value and onValueChange provide controlled state; defaultValue is the local alternative.
  • readOnly keeps the selected value visible while preventing a new choice.

API

Component API
PropTypeDefaultDescriptionConstraints
RadioGroupRoot propsProvides shared value and keyboard state.Give the group an accessible name.
RadioGroupItemvalue + item propsOne mutually exclusive option.Use a stable unique value and visible label.
RadioGroupItem size"sm" | "md" | "lg""md"Control density for the radio and its dot.Match the surrounding form rhythm.
value / defaultValueunknownControlled or initial group value.Do not mix controlled and uncontrolled models.
onValueChange(value, details) => voidCalled when a different item is selected.Update feature state for controlled groups.
disabled / readOnly / requiredbooleanfalseGroup and form interaction semantics.Explain unavailable choices when needed.
name / form / inputRefstring / RefNative form integration.Use name when the group is submitted by a form.

Tokens

Component tokens
TokenRoleEffective valueUsage
--radius-full / --color-border-strongRadio shapesemantic rolesKeeps the circular control legible across sizes.
--radius-full / --color-action-primarySelected indicatorsemantic rolesCommunicates one selected value without color-only meaning.
--focus-ring-*Keyboard focusshared ringKeeps roving focus visible.

Accessibility

  • The group needs a name and each item needs a readable label.
  • Test Arrow keys, Home/End where supported, and Tab order with a keyboard.
  • Do not use a radio group for actions that take effect independently.
  • Select is better for a long option list.
  • Checkbox supports independent choices.
  • Field supplies labels and descriptions.