Skip to main content

Radio group

<zeno-radio-group>FormsForm controlSource

A set of zeno-radio elements with one value, a legend and arrow-key navigation.

import '@usezeno/tokens/css';
import '@usezeno/core/web-components';

Examples​

Basic group​

The value of the group picks the checked radio. The group fires one input and one change event when the choice changes.

Chosen: standard

<zeno-radio-group label="Delivery" name="delivery" value="standard" helper-text="Express orders placed before noon arrive the next day.">
<zeno-radio value="standard" label="Standard delivery"></zeno-radio>
<zeno-radio value="express" label="Express delivery"></zeno-radio>
<zeno-radio value="pickup" label="Pick up in store"></zeno-radio>
</zeno-radio-group>
<p data-result>Chosen: standard</p>
document.querySelector('zeno-radio-group').addEventListener('change', event => {
document.querySelector('[data-result]').textContent = 'Chosen: ' + event.detail.value;
});

Horizontal, and sizes​

The size of the group is given to every radio in it.

<zeno-radio-group label="Small" orientation="horizontal" size="sm" value="month">
<zeno-radio value="month" label="Monthly"></zeno-radio>
<zeno-radio value="year" label="Yearly"></zeno-radio>
</zeno-radio-group>
<zeno-radio-group label="Medium" orientation="horizontal" size="md" value="month">
<zeno-radio value="month" label="Monthly"></zeno-radio>
<zeno-radio value="year" label="Yearly"></zeno-radio>
</zeno-radio-group>
<zeno-radio-group label="Large" orientation="horizontal" size="lg" value="month">
<zeno-radio value="month" label="Monthly"></zeno-radio>
<zeno-radio value="year" label="Yearly"></zeno-radio>
</zeno-radio-group>

Disabled​

A disabled group disables every radio. A single disabled radio is skipped by the arrow keys.

<zeno-radio-group label="Plan" value="basic" disabled>
<zeno-radio value="basic" label="Basic"></zeno-radio>
<zeno-radio value="team" label="Team"></zeno-radio>
</zeno-radio-group>
<zeno-radio-group label="Seats" value="5">
<zeno-radio value="5" label="5 seats"></zeno-radio>
<zeno-radio value="10" label="10 seats" disabled></zeno-radio>
<zeno-radio value="25" label="25 seats"></zeno-radio>
</zeno-radio-group>

With an error​

<zeno-radio-group label="Plan" error="Choose a plan to continue.">
<zeno-radio value="basic" label="Basic"></zeno-radio>
<zeno-radio value="team" label="Team"></zeno-radio>
</zeno-radio-group>

In a form​

The group is the form control: it sends one value under name. A required group blocks the submit until a radio is checked.

Save changes Reset

Nothing submitted yet.

<form>
<zeno-radio-group label="Contact me by" name="contact" required>
<zeno-radio value="email" label="Email"></zeno-radio>
<zeno-radio value="phone" label="Phone"></zeno-radio>
<zeno-radio value="post" label="Post"></zeno-radio>
</zeno-radio-group>
<zeno-button type="submit">Save changes</zeno-button>
<zeno-button type="reset" variant="ghost">Reset</zeno-button>
<p data-result>Nothing submitted yet.</p>
</form>
const form = document.querySelector('form');
form.addEventListener('submit', event => {
event.preventDefault();
const sent = [...new FormData(form)].map(([name, value]) => name + '=' + value);
document.querySelector('[data-result]').textContent = 'Submitted: ' + sent.join('&');
});

Attributes and properties​

PropertyAttributeTypeDefaultDescription
helperTexthelper-textstring
orientationorientationreflects'horizontal' | 'vertical''vertical'
sizesizereflects'sm' | 'md' | 'lg''md'
valuevalueFormValue'' From FormFieldMixin.
namenamereflectsstring From FormFieldMixin.
requiredrequiredreflectsbooleanfalse From FormFieldMixin.
disableddisabledreflectsbooleanfalse From FormFieldMixin.
readonlyreadonlyreflectsbooleanfalse From FormFieldMixin.
errorerrorstringAn error to show, for example one a server returned. From FormFieldMixin.
labellabelstringA visible label. An outside <label for> works as well. From FormFieldMixin.
hideRequiredIndicatorhide-required-indicatorbooleanfalse From FormFieldMixin.
touchedbooleanfalseTrue once the user has left the control or a submit was refused. From FormFieldMixin.
dirtybooleanfalseTrue once the user has changed the value. From FormFieldMixin.
defaultValueFormValue''The value the control goes back to when its form is reset. From FormFieldMixin.
formread onlyHTMLFormElement | null From FormFieldMixin.
labelsread onlyNodeList From FormFieldMixin.
validityread onlyValidityState From FormFieldMixin.
validationMessageread onlystring From FormFieldMixin.
willValidateread onlyboolean From FormFieldMixin.
isDisabledread onlybooleanTrue when the element or an ancestor fieldset disables it. From FormFieldMixin.
invalidread onlybooleanTrue when the control should look invalid. From FormFieldMixin.
testIdstringTest ID for automated testing From ZenoElement.

Methods​

MethodDescription
focus(options?: FocusOptions): voidFocus the component or its first focusable element From ZenoElement.
checkValidity(): booleanReports whether the value is valid without showing anything. Use reportValidity() or validate() to show the result as well. From FormFieldMixin.
reportValidity(): boolean From FormFieldMixin.
setCustomValidity(message: string): void From FormFieldMixin.
validate(): booleanChecks validity and shows the result on the control. From FormFieldMixin.
blur(): voidBlur the component or its focused element From ZenoElement.

Events​

EventDetailDescription
input{ value: FormValue }The user selected a different radio.
change{ value: FormValue }The user selected a different radio.

Slots​

SlotDescription
DefaultThe zeno-radio elements.

CSS parts​

Part
base
error
helper
label
legend
options
required

CSS custom properties​

This element documents no custom properties of its own. Style it through its parts and through the tokens it reads.

The element's own source reads no tokens.

Types​

type FormValue = string | number | boolean | Date | null | undefined;

Accessibility​

Keyboard​

KeyWhat it does
TabMoves focus into the group, to the checked radio or to the first enabled radio when none is checked. Tab again leaves the group.
ArrowDownArrowRightMoves focus to the next enabled radio and checks it. Wraps from the last radio to the first.
ArrowUpArrowLeftMoves focus to the previous enabled radio and checks it. Wraps from the first radio to the last.
SpaceChecks the focused radio.

Forms​

  • With a name, the element adds its value to the data of the form it is in, and is left out while it is disabled.
  • It is labelled by its label attribute or by a <label for> that points at its id.
  • It takes part in validation: checkValidity(), reportValidity() and setCustomValidity() work, and an invalid element blocks the submit and matches :invalid.
  • It follows a <fieldset disabled> around it and goes back to its first value when the form is reset.
  • The messages it writes itself, such as “Please fill out this field.”, are in English only.

Notes​

  • Renders a <fieldset> with role="radiogroup". The label is its <legend> and names the group. Without label, the name comes from aria-label on the element.
  • The group carries aria-required and aria-invalid. The helper text and the error text are linked with aria-describedby.
  • The group has one Tab stop, as a set of native radios does.
  • The group is the form control. It holds the value, checks required and resets. When a submit is refused, the message points at the first enabled radio.

Tests and known gaps​

  • Tested in a real browser by radio.test.ts.
  • Checked with axe-core in the light and the dark theme.
  • Has no Storybook story.
23 of the 38 properties, methods, events, slots and parts above have no description in the source
  • the property helperText
  • the property orientation
  • the property size
  • the property value
  • the property name
  • the property required
  • the property disabled
  • the property readonly
  • the property hideRequiredIndicator
  • the property form
  • the property labels
  • the property validity
  • the property validationMessage
  • the property willValidate
  • the method reportValidity()
  • the method setCustomValidity()
  • the part base
  • the part error
  • the part helper
  • the part label
  • the part legend
  • the part options
  • the part required

Known gaps:

  • Radios must be direct children of the group. A radio wrapped in another element is not managed by the group and is also left out of the form.
  • The checked and size attributes of a radio inside a group are overwritten. The choice comes only from the value of the group.
  • The arrow keys do not skip a radio that is loading. Focus cannot move to it, so the keys stop at the radio before it.
  • Home and End do not move to the first and last radio.
  • readonly is declared but does nothing. The choice can still be changed.
  • A disabled group is dimmed twice, once on the group and once on each radio, so the radios are much lighter than other disabled controls.
  • A disabled group is not announced as disabled itself. Only the radios inside it are.
  • The required message “Please select one of these options.” is English only. An error text replaces it.
  • The error text is not a live region. An error that appears while the user is elsewhere is not announced.
  • The gap before the required star uses margin-left, so it is on the wrong side in a right-to-left page.