Forms & Input
Switch
AvailableAn on/off toggle. Covers the difference from checkbox and how to use role="switch".
What is a Switch?
A switch is a UI control that toggles between two states: on and off. It is commonly used for settings that take effect immediately, such as Wi-Fi, notifications, and dark mode.
While similar to a checkbox, a switch carries a stronger connotation ofan immediate, real-time toggle. In many cases either control is appropriate, and you can implement a switch using either a native <input type="checkbox"> or role="switch".
Why Does Accessibility Matter?
A "visual-only toggle" fails to convey its state to the following users:
- Keyboard users. A
<div>cannot receive focus, making it impossible to toggle. - Screen reader users. Without
role="switch"andaria-checked, the control is not announced as a "switch" nor as "on/off," leaving the current state unknown.
The key is to always convey the role (switch) and state (aria-checked) in code. Relying solely on visual cues like color or position is not sufficient.
Live Demo (Recommended Implementation)
The switch below follows the APG specification.Without using a mouse, press Tab to focus it and Enter / Space to toggle.
Try it: Tab to focus → both Enter and Space toggle on/off, and the state text updates accordingly.
Tip
When a screen reader focuses the switch, it announces something like "Wi-Fi, switch, off," and when toggled, it changes to "on." This is the effect of role="switch" andaria-checked (the "Off/On" text on the right is a visual aid for sighted users and is marked with aria-hidden to avoid duplicate announcements).
Keyboard Interaction
| Key | Action | Priority |
|---|---|---|
| Tab | Move focus to the next / previous switch | Required |
| Space | Toggle on / off | Required |
| Enter | Toggle on / off (works automatically if based on <button>) | Optional |
Note
Using a <button> as the base element means both Enter and Spacework automatically. All you need to do is toggle aria-checked in the click handler.
Required WAI-ARIA Roles and Properties
| Target | Attribute / Role | Meaning |
|---|---|---|
| Switch element | <button> + role="switch" | Identifies the element as a switch. Using a button base provides automatic focus and keyboard handling. |
| Switch element | aria-checked="true | false" | On / off state. Must be updated on every toggle. |
| Switch element | aria-labelledby or aria-label | Provides a label describing what the switch controls. |
| Decorative thumb | aria-hidden="true" | Excludes the purely visual element from screen reader output. |
Note
For a simpler approach, you can also use a native <input type="checkbox" role="switch">with a <label>. In that case, you don't need to manage aria-checked manually — the browser's native checked property handles it.
Recommended Pattern (Good)
Good / Recommended
Use a <button role="switch"> as the base and keep aria-checked in sync with the state.
Markup:
<!-- Place the label and switch side by side -->
<span id="wifi-label">Wi-Fi</span>
<button type="button"
role="switch"
aria-checked="false"
aria-labelledby="wifi-label"
id="wifi-switch"
class="switch">
<span class="switch-thumb" aria-hidden="true"></span>
</button>Toggle script (updating aria-checked is all you need):
const sw = document.getElementById('wifi-switch');
if (sw) {
// Since it's a button, just listen for click (mouse, Enter, Space)
sw.addEventListener('click', () => {
const on = sw.getAttribute('aria-checked') === 'true';
// Toggle the state and always update aria-checked
sw.setAttribute('aria-checked', String(!on));
});
}Note
For the visual appearance (thumb position and color), use CSS selectors based on the aria-checkedvalue (e.g., [aria-checked="true"]) so the style always matches the state. Avoid indicating state with color alone — also differentiate by shape and position.
Anti-pattern (Bad)
The example below is a toggle that only changes the visual appearance of a <div>.It works with a mouse, but cannot be reached via keyboard, and the state is not communicated to assistive technologies.
Try it: Tab cannot reach it, and Space does nothing. Screen readers do not announce it as a 'switch' or convey on/off state.
<!-- ❌ Anti-pattern: visual-only toggle -->
<div class="toggle" onclick="this.classList.toggle('on')">
<div class="knob"></div>
</div>Bad / Avoid
Problems with this implementation:
- Not keyboard operable — A
divcannot receive focus. - Role not communicated — Without
role="switch", it is not recognized as a switch. - State not communicated — Without
aria-checked, the on/off state cannot be determined. - No accessible name — The purpose of the switch (Wi-Fi) is not programmatically associated.
Tip
Avoid indicating state with color alone (it may not be perceivable by users with color vision deficiencies). Combine color with other visual cues such as thumb position or an ON/OFF label.
Implementation Checklist
- Switch element is based on <button> (or <input type="checkbox">)
- role="switch" is applied (when using a button base)
- aria-checked always matches the on/off state
- A label is provided via aria-labelledby or aria-label
- Decorative thumb has aria-hidden="true"
- Space toggles the switch (Enter is optional; automatic with <button>), and focus is visible
- State is conveyed not only by color but also by position and/or label
Source (English):Switch Pattern — W3C APG(opens in a new tab)