Skip to main content

Radio

A grouped single-choice control — a RadioGroup that owns the selected value, wrapping one Radio per option.

Installation​

npm install @sipe-team/radio
import '@sipe-team/radio/styles.css';

Usage​

RadioGroup renders a <fieldset> and shares a name, size, and the selected value through context, so every Radio inside it is wired into one group automatically — picking one clears the rest. Clicking a Radio's label selects it.

Pick a fruit

Examples​

Uncontrolled​

Give RadioGroup a defaultValue and let it track the selection itself — the common case for forms that read the value on submit. RadioGroup generates a name when you do not pass one, so the options are still submitted as a single field.

Shipping

Controlled​

Own the state yourself with value and onChangeValue when another part of the UI has to react to the selection. onChangeValue receives the next value string.

Picked: apple

Sizes​

medium (default) fits most forms; small for dense rows, large for touch targets. Set size on RadioGroup to scale every option, and the dot, font, and spacing all scale together.

Small
Medium
Large

Disabled​

disabled on RadioGroup disables every option via the native <fieldset disabled>; disabled on a single Radio disables just that one. Both dim the affected labels.

Whole group
Single option

Anatomy​

import { Radio, RadioGroup } from '@sipe-team/radio';

export default () => (
<RadioGroup labelText="Label" defaultValue="a">
<Radio value="a">Option A</Radio>
<Radio value="b">Option B</Radio>
</RadioGroup>
);

RadioGroup renders a <fieldset> (with a <legend> when labelText is set) and provides context; each Radio reads from it and renders a <label> wrapping an <input type="radio">. The selected value, name, size, and disabled live on RadioGroup — a Radio should be rendered inside one so the options share a group.

API Reference​

Neither part forwards a ref.

RadioGroup​

Renders a <fieldset>. Provides the selection, name, size, and disabled to its Radio children through context.

PropTypeDefaultDescription
childrenReactNode—Required. The Radio options.
valuestring—Controlled selected value. Pair with onChangeValue.
defaultValuestring—Initial selected value when uncontrolled.
onChangeValue(value: string) => void—Called with the next value when a Radio is chosen.
labelTextstring''Rendered as the fieldset's <legend>. Omitted when empty.
namestringautoShared name for the inputs. Generated via useId when not provided.
size'small' | 'medium' | 'large''medium'Scales the dot, font size, and spacing of every option.
disabledbooleanfalseDisables the whole group via <fieldset disabled>.
classNamestring—Appended to the fieldset class.

Extra props are not spread onto the <fieldset>; only those above are used.

Radio​

Renders a <label> wrapping an <input type="radio">, plus a <span> for the label text when children are given. Reads the selected value, name, size, and group disabled from RadioGroup.

PropTypeDefaultDescription
valuestring—Required. This option's value, compared against the group's value.
childrenReactNode—Label text. When omitted, no <span> is rendered.
size'small' | 'medium' | 'large'group / 'medium'Overrides the group size for this option.
disabledbooleanfalseDisables just this option. The group disabled also forces it on.
defaultCheckedboolean—Marks this option checked when uncontrolled. Usually prefer RadioGroup's defaultValue.
classNamestring—Appended to the <label> (container) class.

Also accepts the rest of ComponentProps<'input'> except size (onChange, required, id, …), spread onto the underlying <input>. name and checked are supplied by RadioGroup.

Accessibility​

  • RadioGroup renders a native <fieldset>; labelText becomes its <legend>, labelling the group for screen readers.
  • Each Radio is a native <input type="radio"> sharing the group's name, so the browser provides roving focus and arrow-key navigation between options for free.
  • Every Radio wraps its <input> in a <label> with a matching generated id, so clicking the label selects the option.
  • disabled sets the native disabled attribute (on the <fieldset> for the group, or the <input> for a single option).

Known limitations​

  • Radio uses hardcoded light-surface colors (constants/colors.ts) rather than theme-driven tokens, so it does not adapt to this dark-only docs site. The demos above are shown on a light card so the control renders as intended; on a dark background its text would be illegible.
  • RadioGroup always stacks its options vertically (flex-direction: column); there is no orientation prop for a horizontal layout.