Radio group
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.
<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
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
helperText | helper-text | string | ||
orientation | orientationreflects | 'horizontal' | 'vertical' | 'vertical' | |
size | sizereflects | 'sm' | 'md' | 'lg' | 'md' | |
value | value | FormValue | '' | From FormFieldMixin. |
name | namereflects | string | From FormFieldMixin. | |
required | requiredreflects | boolean | false | From FormFieldMixin. |
disabled | disabledreflects | boolean | false | From FormFieldMixin. |
readonly | readonlyreflects | boolean | false | From FormFieldMixin. |
error | error | string | An error to show, for example one a server returned. From FormFieldMixin. | |
label | label | string | A visible label. An outside <label for> works as well. From FormFieldMixin. | |
hideRequiredIndicator | hide-required-indicator | boolean | false | From FormFieldMixin. |
touched | boolean | false | True once the user has left the control or a submit was refused. From FormFieldMixin. | |
dirty | boolean | false | True once the user has changed the value. From FormFieldMixin. | |
defaultValue | FormValue | '' | The value the control goes back to when its form is reset. From FormFieldMixin. | |
formread only | HTMLFormElement | null | From FormFieldMixin. | ||
labelsread only | NodeList | From FormFieldMixin. | ||
validityread only | ValidityState | From FormFieldMixin. | ||
validationMessageread only | string | From FormFieldMixin. | ||
willValidateread only | boolean | From FormFieldMixin. | ||
isDisabledread only | boolean | True when the element or an ancestor fieldset disables it. From FormFieldMixin. | ||
invalidread only | boolean | True when the control should look invalid. From FormFieldMixin. | ||
testId | string | Test ID for automated testing From ZenoElement. |
Methods
| Method | Description |
|---|---|
focus(options?: FocusOptions): void | Focus the component or its first focusable element From ZenoElement. |
checkValidity(): boolean | Reports 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(): boolean | Checks validity and shows the result on the control. From FormFieldMixin. |
blur(): void | Blur the component or its focused element From ZenoElement. |
Events
| Event | Detail | Description |
|---|---|---|
input | { value: FormValue } | The user selected a different radio. |
change | { value: FormValue } | The user selected a different radio. |
Slots
| Slot | Description |
|---|---|
| Default | The 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
| Key | What it does |
|---|---|
| Tab | Moves focus into the group, to the checked radio or to the first enabled radio when none is checked. Tab again leaves the group. |
| ArrowDownArrowRight | Moves focus to the next enabled radio and checks it. Wraps from the last radio to the first. |
| ArrowUpArrowLeft | Moves focus to the previous enabled radio and checks it. Wraps from the first radio to the last. |
| Space | Checks 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
labelattribute or by a<label for>that points at itsid. - It takes part in validation:
checkValidity(),reportValidity()andsetCustomValidity()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>withrole="radiogroup". Thelabelis its<legend>and names the group. Withoutlabel, the name comes fromaria-labelon the element. - The group carries
aria-requiredandaria-invalid. The helper text and the error text are linked witharia-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
requiredand 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
checkedandsizeattributes of a radio inside a group are overwritten. The choice comes only from thevalueof 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.
readonlyis 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
errortext 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.