Forms & Input

Switch

Available

An 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:

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.

Accessible Switch
Wi-Fi

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

KeyActionPriority
TabMove focus to the next / previous switchRequired
SpaceToggle on / offRequired
EnterToggle 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

TargetAttribute / RoleMeaning
Switch element<button> + role="switch"Identifies the element as a switch. Using a button base provides automatic focus and keyboard handling.
Switch elementaria-checked="true | false"On / off state. Must be updated on every toggle.
Switch elementaria-labelledby or aria-labelProvides a label describing what the switch controls.
Decorative thumbaria-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.

Visual-only broken toggle
Wi-Fi

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 div cannot 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


Source (English):Switch Pattern — W3C APG(opens in a new tab)