Video examples

iOS Voiceover Safari

Windows Jaws Chrome

Windows NVDA Chrome

MacOS Voiceover Safari

Code examples

Use as much semantic HTML as possible

This semantic HTML contains all accessibility features by default, and only requires the addition of role="switch".

<fieldset>
  <legend>Activate your options:</legend>
  <input type="checkbox" role="switch" id="alphaSwitch">
  <label for="alphaSwitch">Alpha</label>

  <input type="checkbox" role="switch" id="bravoSwitch">
  <label for="bravoSwitch">Bravo</label>

  <input type="checkbox"
         role="switch"
         id="charlieSwitch"
         checked>
  <label for="charlieSwitch">Charlie</label>
</fieldset>
Activate your options:

Disabled states

If it’s helpful for screenreaders to perceive a disabled toggle, use aria-disabled="true" and prevent click events with scripting.

<input type="checkbox"
        role="switch"
        id="deltaSwitch"
        aria-disabled="true"
        checked>
<label for="deltaSwitch">Delta</label>

Using the disabled attribute will prevent the input from being clickable, but will also prevent it from being focusable, making it more difficult to discover for screenreaders.

<input type="checkbox"
        role="switch"
        id="deltaSwitch"
        disabled
        checked>
<label for="deltaSwitch">Delta</label>

You can also use a button

This <button> toggle has focus and keyboard criteria built in. It requires the addition of role="switch" and scripting to toggle aria-checked="true/false".

<button role="switch" aria-checked="true">
  Alpha
</div>

When you can’t use semantic HTML

This custom switch requires extra attributes and keyboard event listeners.

<div role="switch" tabindex="0" aria-checked="true">
  Alpha
</div>

Developer notes

Name

  • label text should describe the input.
  • Use aria-describedby="hint-id" for hints or additional descriptions
  • aria-label="Switch purpose" can also be used (as a last resort)

Role

  • Use role="switch"

Group

  • Semantic HTML
    • <fieldset> should wrap a switch group
    • <legend> should describe the group’s purpose
    • Each <label> must include for="input-id" to be associated with its input
  • Custom elements
    • Use role="group" in the palace of fieldset
    • Use aria-labelledby="label-id" to associate an element as a label
    • aria-label="Group purpose" can also be used if there’s no label with an ID

State

  • Semantic HTML
    • Use checked for native HTML
    • Use the disabled state for inactive switches
  • Custom element
    • Use aria-checked="true/false" to express state
    • Use aria-disabled="true" to declare inactive elements
    • Use aria-readonly="true" to declare a switch can’t be edited

Focus

  • Focus must be visible