Skip to main content

Radio

<zeno-radio>FormsForm controlSource

One choice of a set. Put several in a zeno-radio-group, or give them the same name.

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

Examples​

Radios that share a name​

Radios with the same name uncheck each other. For a set with a legend, arrow keys and one error, put the radios in a zeno-radio-group.

<zeno-radio name="delivery" value="standard" label="Standard delivery" checked></zeno-radio>
<zeno-radio name="delivery" value="express" label="Express delivery"></zeno-radio>
<zeno-radio name="delivery" value="pickup" label="Pick up in store"></zeno-radio>

Sizes​

<zeno-radio name="size" size="sm" label="Small" checked></zeno-radio>
<zeno-radio name="size" size="md" label="Medium"></zeno-radio>
<zeno-radio name="size" size="lg" label="Large"></zeno-radio>

States​

loading shows a spinner in the circle and disables the radio. An error marks the radio invalid and shows the text under it.

<zeno-radio label="Disabled" disabled></zeno-radio>
<zeno-radio label="Disabled and checked" disabled checked></zeno-radio>
<zeno-radio label="Loading" loading></zeno-radio>
<zeno-radio label="With an error" error="This option is no longer available."></zeno-radio>

In a form​

Only the checked radio is sent, under name. A reset brings back the radio that was checked at the start.

Save changes Reset

Nothing submitted yet.

<form>
<zeno-radio name="contact" value="email" label="Email" checked></zeno-radio>
<zeno-radio name="contact" value="phone" label="Phone"></zeno-radio>
<zeno-radio name="contact" value="post" label="Post"></zeno-radio>
<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
checkedcheckedreflectsbooleanfalse
sizesizereflects'sm' | 'md' | 'lg''md'
loadingloadingreflectsbooleanfalse
defaultCheckedbooleanfalseWhether it is checked when its form is reset.
valuevalueFormValue'on' 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.
blur(): voidBlur the component or its focused 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.

Events​

EventDetailDescription
input{ checked: boolean; value: FormValue }The user selected the radio.
change{ checked: boolean; value: FormValue }The user selected the radio.

Slots​

This element has no slots.

CSS parts​

Part
base
button
dot
error
label
loading
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 to the radio. Outside a zeno-radio-group every radio is a Tab stop.
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 native <input type="radio"> in its shadow root, inside a <label> that holds the label text. A click on the text checks the radio.
  • Without label, the name comes from aria-label on the element or from an outside <label for>.
  • The input always carries aria-invalid. When an error shows, aria-describedby points at the error text.
  • The native input is invisible but still focusable. The focus ring is drawn on the circle.
  • The required star is hidden from assistive technology.

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 checked
  • the property size
  • the property loading
  • 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 button
  • the part dot
  • the part error
  • the part label
  • the part loading
  • the part required

Known gaps:

  • Outside a zeno-radio-group, radios with one name are not a keyboard group. Every radio is a Tab stop and the arrow keys do not move between them. Assistive technology does not announce “1 of 3”.
  • There is no slot. The label is plain text from label, and content placed inside the element is not shown.
  • readonly is declared but does nothing. A read-only radio can still be changed.
  • Outside a group, required works for each radio alone. Every required radio shows its own star, and after a refused submit every one of them shows the same error text.
  • Inside a zeno-radio-group the error of a single radio is not shown.
  • loading disables the inner input, so the radio cannot take focus while it loads. The spinner is announced as “Loading”, in English, and the input has no aria-busy.
  • 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.