Switch
A switch is a control with two mutually exclusive states — on or off —
that takes effect immediately, like a physical light switch. It carries
role="switch" and an aria-checked value of
true or false, and it always has an accessible name so a
screen-reader user hears Wi-Fi, switch, on
rather than an unlabelled toggle.
Prefer a native control when one fits: an HTML
<input type="checkbox"> already exposes a checked state to assistive
technology, and styling it as a switch (optionally with role="switch") is
the most robust route inside forms. Build the button-based switch below when you need
an immediate setting that is not submitted with a form. It follows the
WAI-ARIA Authoring
Practices switch pattern; switch.js enhances authored markup, and with
scripting off the control is still a labelled button.
Live demo
Move focus to the switch with Tab, then press Space or
Enter to flip it. The state changes in three independent ways — the
thumb slides, the track fills, and the word beside it reads On
or
Off
— so it never depends on colour alone.
When to use
Reach for a switch — or a checkbox?
- Use a switch for an on/off setting that applies
immediately, like
Dark mode
orWi-Fi
. - Use a checkbox for a selection — agreeing to terms, picking items, or anything submitted later with a form.
- Prefer native HTML: a styled
<input type="checkbox">gives you the checked state, keyboard, and label wiring for free. - Whatever you choose, the control must keep a real, visible accessible name — the visible text label, not a placeholder or icon alone.
Markup
Author the button with its role, state, and label in place, then let
switch.js toggle aria-checked on activation. Because it is a
real <button>, Space and Enter fire a click
natively — no extra key handling is needed.
<button type="button" class="ewa-switch" role="switch"
aria-checked="false" data-switch>
<span class="ewa-switch__text">Email notifications</span>
<span class="ewa-switch__track" aria-hidden="true">
<span class="ewa-switch__thumb"></span>
</span>
<span class="ewa-switch__state" data-switch-state aria-hidden="true">Off</span>
</button>
Keyboard interactions
The switch is a single focusable control. Because it is a button, the platform handles activation keys for you — there is no custom key handling to maintain.
| Key | Action |
|---|---|
| Tab | Moves focus to the switch (and away again to the next control). |
| Space | Toggles the switch on or off. |
| Enter | Toggles the switch on or off. |
ARIA roles, states, and properties
The button takes the switch role and reports its on/off state through
aria-checked. Its accessible name comes from the visible text inside the
button, so the label and the control can never drift apart.
| Attribute | On | Purpose |
|---|---|---|
role="switch" |
Button | Identifies the control as an on/off switch rather than a plain button. |
aria-checked="true" |
Button | The switch is on. Set when the setting is active. |
aria-checked="false" |
Button | The switch is off. The attribute is always present, never omitted. |
| Accessible name | Button | The visible label text inside the button names the switch (e.g.
Email notifications); no separate aria-label needed. |
aria-hidden="true" |
Track & state word | Hides the purely visual track, thumb, and duplicated On/Offword from AT — the role and state already convey on/off. |
Common mistakes
Pitfalls to avoid
- Using a switch where a checkbox belongs. A switch is for an immediate on/off setting; a checkbox is for selection, usually submitted with a form. Picking the wrong one mismatches the user’s mental model and the announced role.
- Relying on colour alone for the state. A green-vs-grey track is
invisible to many users — keep the accessible name plus an
on/off cue beyond hue, such as the thumb position and an
On/Off
word. - Dropping the accessible name. An icon or bare track is not a label; the switch needs visible text that names what it controls.
- Omitting
aria-checkedwhen off. The attribute must always be present astrueorfalse, never absent. - Moving focus on toggle. Flipping the switch must change only the state; focus stays on the control so keyboard users keep their place.