Radio Group
import { RadioGroup } from '@absoluteui/components/radio-group';import '@absoluteui/components/radio-group/style.css';Using Angular? See Radio Group for Angular.
What it does
Section titled “What it does”Exactly one choice from a short set of mutually exclusive options. RadioGroup renders a <fieldset role="radiogroup"> and <legend> around native radios that share one name (generated when name is absent), so the browser provides the single tab stop and arrow-key selection. It adds group help text, required validation, and one localized validation message.
When to use
Section titled “When to use”- Choosing one option from 2 to about 7 visible options where comparing them matters.
- A required choice with no sensible default.
When not to use
Section titled “When not to use”- Several independent choices: use Checkbox Group.
- Long or searchable lists: use Select or Combobox.
- A binary setting that applies immediately: use Switch.
Examples
Section titled “Examples”Required choice with option descriptions
Section titled “Required choice with option descriptions”import { RadioGroup } from '@absoluteui/components/radio-group';
const host = document.createElement('div');document.body.append(host);const shipping = RadioGroup.create(host, { label: 'Shipping speed', name: 'shipping', required: true, options: [ { value: 'standard', label: 'Standard', description: '3 to 5 business days' }, { value: 'express', label: 'Express', description: 'Next business day' }, ],});host.addEventListener('aui-change', () => { host.dataset.shipping = shipping.value ?? '';});Horizontal group with a disabled option
Section titled “Horizontal group with a disabled option”import { RadioGroup } from '@absoluteui/components/radio-group';
const host = document.createElement('div');document.body.append(host);RadioGroup.create(host, { label: 'Size', orientation: 'horizontal', value: 'm', options: [ { value: 's', label: 'Small' }, { value: 'm', label: 'Medium' }, { value: 'l', label: 'Large', disabled: true }, ],});Show messages only on submit
Section titled “Show messages only on submit”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { radioGroup: { validationTiming: 'submit' } } });import { RadioGroup } from '@absoluteui/components/radio-group';import '@absoluteui/components/radio-group/style.css';
const host = document.querySelector<HTMLElement>('#size');if (host) { const size = RadioGroup.create(host, { label: 'Size', orientation: 'horizontal', options: [ { value: 's', label: 'Small' }, { value: 'm', label: 'Medium' }, { value: 'l', label: 'Large' }, ], }); host.addEventListener('aui-change', () => { host.dataset.size = size.value ?? ''; });}More usage
Section titled “More usage”import { RadioGroup } from '@absoluteui/components/radio-group';
const host = document.createElement('div');document.body.append(host);RadioGroup.create(host, { label: 'Shipping speed', name: 'shipping', required: true, options: [ { value: 'standard', label: 'Standard' }, { value: 'express', label: 'Express' }, ],});Anatomy
Section titled “Anatomy”<div class="aui-field aui-radio-group" data-aui-control> (consumer host) <fieldset class="aui-radio-group__fieldset" role="radiogroup" aria-labelledby=legend aria-required aria-invalid aria-describedby> <legend class="aui-field__label">Label<span class="aui-field__required" aria-hidden="true">*</span></legend> <div class="aui-field__description"> (optional) <div class="aui-radio-group__options"> <div class="aui-radio-group__option"> (per option) <span class="aui-radio-group__box"> <input type="radio" class="aui-radio-group__input" name value> <span class="aui-radio-group__dot" aria-hidden="true"> </span> <div class="aui-radio-group__text"> <label class="aui-radio-group__label" for=input> <div class="aui-radio-group__option-description"> (optional) </div> </div> </div> <div class="aui-field__error aui-validation-message"> (when shown) </fieldset></div>API reference
Section titled “API reference”Factory
Section titled “Factory”RadioGroup.create(host: HTMLElement, options: RadioGroupOptions): RadioGroupGlobal configuration key: radioGroup (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Legend text and accessible name of the radiogroup. Required. | |
hideLabel |
boolean |
false |
Visually hide the legend; it remains the accessible name. |
options |
readonly { value: string; label: string; description?: string; disabled?: boolean }[] |
Choices; values must be unique. Required. | |
value |
string | null |
"null" |
Initially selected value; also restored by reset(). |
name |
string |
Native radio name; a unique name is generated when absent. | |
description |
string |
Group help text referenced by the radiogroup’s aria-describedby. | |
required |
boolean |
false |
A selection is required (aria-required on the radiogroup, native required on radios). |
orientation |
'vertical' | 'horizontal' |
"vertical" |
Layout of the options. |
disabled |
boolean |
false |
Disables the whole group (fieldset disabled). |
validate |
(value: string | null) => string | null |
Consumer validation; return a message to mark the selection invalid. | |
icons |
Partial<{ error: IconRef }> |
Icon slot overrides. | |
validationTiming |
'blur' | 'input' | 'submit' |
"blur" |
When validation messages first appear; afterwards they update live. Globally configurable. |
locale |
string |
"en-US" |
Message locale. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. |
fieldset |
HTMLFieldSetElement |
The fieldset with role=radiogroup. |
inputs |
HTMLInputElement[] |
The native radios, in option order. |
value |
string | null |
Selected value, or null. |
name |
string | null |
Consumer form field name (null when generated). |
label |
string |
Legend text. |
disabled |
boolean |
Group disabled state. |
validity |
FieldValidity |
{ valid, error, message }; computed on every change. |
dirty |
boolean |
Selection differs from the initial selection. |
touched |
boolean |
Focus has left the group at least once. |
options |
Readonly<RadioGroupOptions> |
Current instance options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setValue(value: string | null): void |
Programmatic selection (no events); null clears it; unknown values throw RADIO_GROUP_OPTIONS. |
update(options: Partial<RadioGroupOptions>): void |
Merge and apply options; a new option list keeps the selection if it still exists. |
reportValidity(): boolean |
Show messages now and return validity. |
setCustomError(message: string | null): void |
External error; cleared when the selection changes. |
getFormValue(): string | null |
Selected value for form serialization. |
focus(): void |
Focus the selected radio, else the first enabled radio. |
reset(): void |
Restore the initial selection and clear dirty/touched/submitted state. |
destroy(): void |
Remove rendering, listeners, registration, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ value: string | null; validity: FieldValidity } |
Yes | No | The user selected an option (click, Space, or arrow keys). |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-field aui-radio-group |
Host. |
aui-radio-group--invalid | --disabled |
State modifiers on the host. |
aui-field__label | __required | __description | __error |
Shared field chrome (the label is the legend). |
aui-radio-group__fieldset |
Fieldset with role=radiogroup. |
aui-radio-group__options | __options--horizontal |
Option list and its horizontal layout. |
aui-radio-group__option |
One option row. |
aui-radio-group__box | __input | __dot |
Radio wrapper, native input, and selected dot. |
aui-radio-group__text | __label | __option-description |
Option label and help text. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
error |
alert-circle |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-on-primary | --aui-color-primary | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-md | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-space-1 | --aui-space-2 | --aui-space-4 | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”type RadioGroupOrientation = 'vertical' | 'horizontal';interface RadioGroupOption { value: string; label: string; description?: string; disabled?: boolean }interface RadioGroupIcons { error: IconRef }interface RadioGroupChangeDetail { value: string | null; validity: FieldValidity }Accessibility
Section titled “Accessibility”Pattern: Native radios sharing one name inside <fieldset role=“radiogroup”> + <legend> (WAI-ARIA APG Radio Group, native keyboard model).
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Moves focus into the group (selected radio, else the first enabled radio) and out of it; the group is one tab stop. |
| ArrowDown / ArrowRight | Radio focused | Moves to and selects the next enabled radio, wrapping (native). |
| ArrowUp / ArrowLeft | Radio focused | Moves to and selects the previous enabled radio, wrapping (native). |
| Space | Unselected radio focused | Selects the focused radio (native). |
| Element | Role |
|---|---|
| fieldset | radiogroup (explicit), named by the legend via aria-labelledby |
| input | radio (native) |
| selected dot and icons | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-labelledby |
fieldset | Legend id |
aria-required |
fieldset | “true” when required |
aria-invalid |
fieldset | “true” only while an error message is shown |
aria-describedby |
fieldset | Group help text and visible error message ids |
aria-describedby |
input | That option’s help text id, when present |
The native radio is the focus target and shows a color-focus-ring outline on :focus-visible.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The required asterisk is aria-hidden; aria-required on the radiogroup and native required on the radios convey the state.
- Selection is shown by an inner dot, not only by the fill color.
- Arrow-key navigation is native: disabled radios are skipped and selection follows focus.
- Errors appear after focus leaves the group by default, not when moving between radios.
- Screen-reader announcement of aria-invalid and aria-describedby on the radiogroup has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Behavior
Section titled “Behavior”States
Section titled “States”default, hover, focus-visible, selected, disabled (group), disabled (option), required, invalid (message shown).
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| any | click, label click, Space, or arrow key | new selection; aui-change; dirty |
| any | focus leaves the group | touched; messages shown (blur timing) |
| any | reportValidity() |
submitted; messages shown for every timing |
| invalid (custom error) | selection changes | custom error cleared |
| any | reset() |
initial selection; pristine, untouched |
Accessibility notes
Section titled “Accessibility notes”- The required asterisk is
aria-hidden;aria-requiredconveys the state. - Selection is shown by an inner dot, not only color.
- Native keyboard behavior is used, so it matches platform conventions and skips disabled radios.
- Errors appear after focus leaves the whole group, not when moving between radios.
- Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”Vertical by default. orientation: 'horizontal' wraps options in a row. Labels and help text wrap; rows are at least touch-target-min tall.
Right-to-left
Section titled “Right-to-left”Logical properties and flex layout: radios are at the inline start and horizontal options flow from the inline start. Arrow keys follow the browser’s native direction handling.
Theming
Section titled “Theming”Colors come from role tokens only. In forced-colors mode rings use Canvas/CanvasText, the selected ring and dot use Highlight, and disabled uses GrayText, with forced-color-adjust: none.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { radioGroup: { validationTiming: 'submit' } } });Changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic; changing options or name rebuilds the radios.
icons.error (default alert-circle). The selected dot is a CSS shape, not an icon.
Security
Section titled “Security”All text uses textContent. Validation messages never include the selected value. CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. With name, the selected radio submits name=value. Without name, a generated name groups the radios; it is not tied to user data.
Performance
Section titled “Performance”Two listeners per instance (delegated change, focusout), a shared document-level pointer tracker, and one configuration subscription. Rendering is linear in the number of options. Target: under 2 ms for 7 options; not yet covered by the performance test.
Supported data scale
Section titled “Supported data scale”Short lists, up to about 20 options. Unit-tested with 4 options.
Edge cases
Section titled “Edge cases”- Once selected, the user cannot clear the selection (native); add a “None” option if needed.
- Two groups with the same consumer
namein one form become one native group. update({ options })clears the selection when its value no longer exists.- A disabled selected option stays selected but is skipped by arrow keys.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
RADIO_GROUP_OPTIONS |
configuration | Missing label, empty or duplicate options, unknown value, empty name, invalid orientation. |
Validation (validity.error) |
validation | value-missing (“Select an option.”), custom. |
A failed construction leaves no rendering, listeners, or subscriptions behind.
Known limitations
Section titled “Known limitations”- The selection cannot be cleared by the user.
- Screen-reader behavior of
aria-invalidand descriptions on the radiogroup has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML in labels or the legend.
- Custom roving focus.
- Read-only radio groups.