Skip to main content

Switch

<zeno-switch>FormsForm controlSource

An on/off switch. It takes part in forms as a native checkbox does.

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

Examples​

Basic​

The label comes from the label attribute. The change event carries the new state in event.detail.checked.

Notifications are on.

<zeno-switch label="Email notifications" checked></zeno-switch>
<p data-result>Notifications are on.</p>
document.querySelector('zeno-switch').addEventListener('change', event => {
document.querySelector('[data-result]').textContent =
'Notifications are ' + (event.detail.checked ? 'on' : 'off') + '.';
});

Sizes​

<zeno-switch size="sm" label="Small"></zeno-switch>
<zeno-switch size="md" label="Medium"></zeno-switch>
<zeno-switch size="lg" label="Large"></zeno-switch>

Label position and icon​

label-position="start" puts the label before the switch. show-icon draws a check mark in the thumb.

<zeno-switch label="Label at the start" label-position="start"></zeno-switch>
<zeno-switch label="With a check icon" show-icon checked></zeno-switch>

States​

A loading switch shows a spinner in the thumb and cannot be changed.

<zeno-switch label="Disabled" disabled></zeno-switch>
<zeno-switch label="Disabled and on" disabled checked></zeno-switch>
<zeno-switch label="Loading" loading></zeno-switch>
<zeno-switch label="With an error" error="Turn this on to continue."></zeno-switch>

In a form​

A switch is sent with the form only when it is on. The value it sends is on unless you set value.

Create account

Nothing submitted yet.

<form>
<zeno-switch name="updates" label="Send me product updates" checked></zeno-switch>
<zeno-switch name="terms" value="accepted" label="I accept the terms" required></zeno-switch>
<zeno-button type="submit">Create account</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
showIconshow-iconreflectsbooleanfalse
labelPositionlabel-positionreflects'start' | 'end''end'
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 turned the switch on or off.
change{ checked: boolean; value: FormValue }The user turned the switch on or off.

Slots​

This element has no slots.

CSS parts​

Part
base
error
icon
label
loading
required
thumb
track

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 switch.
SpaceTurns the switch on or off.

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​

  • The control is a native <input type="checkbox"> with role="switch". The Space key and the on or off state come from it.
  • The input and the label text are inside one <label>, so the text names the switch and a click on the text toggles it. Without label, the name comes from an outside <label for> or from aria-label on the element. A click on an outside label also toggles the switch.
  • A required switch shows * after the label. The mark is hidden from assistive technology, and the native required attribute is set on the input.
  • When the switch is invalid, the input has aria-invalid="true" and aria-describedby points at the error text.

Tests and known gaps​

  • Tested in a real browser by checkbox.test.ts.
  • Checked with axe-core in the light and the dark theme.
  • Has no Storybook story.
26 of the 41 properties, methods, events, slots and parts above have no description in the source
  • the property checked
  • the property size
  • the property loading
  • the property showIcon
  • the property labelPosition
  • 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 icon
  • the part label
  • the part loading
  • the part required
  • the part thumb
  • the part track

Known gaps:

  • The readonly attribute does nothing. A read-only switch can still be turned on and off.
  • While loading, the inner input gets the native disabled attribute. The switch leaves the tab order and reads as unavailable, and it has no aria-busy.
  • The label can only be plain text from the label attribute. There is no slot, so the label cannot hold a link or other markup.