Video examples

iOS Voiceover

Android Talkback

Windows Jaws Chrome

Windows NVDA Chrome

MacOS Voiceover Safari

Code examples

Use semantic HTML

  • This semantic HTML contains all accessibility features by default.
  • It uses CSS pseudo attributes to create the checkbox indicator, no Javascript.
<fieldset>
  <legend>Choose your favorite NATO letters:</legend>

  <input type="checkbox" id="alphaCheckbox">
  <label for="alphaCheckbox">Alpha</label>

  <input type="checkbox" id="bravoCheckbox">
  <label for="bravoCheckbox">Bravo</label>

  <input type="checkbox" id="charlieCheckbox" checked>
  <label for="charlieCheckbox">Charlie</label>
</fieldset>
Choose your favorite NATO letters:

Don’t put interactive elements inside the label

Even though this is valid HTML, it creates unpredictable results with screenreaders. A (currently) reliable method is to keep interactive elements outside the label and reference it with aria-describedby="hint-id"

<fieldset>
  <legend>Legal disclaimers</legend>
  <div id="hint-tc" class="hint-checkbox">
    <a href="/code-of-conduct/">Read terms and conditions</a>
  </div>
  <input type="checkbox"
         id="tc-agree"
         aria-describedby="hint-tc">
  <label for="tc-agree">
    I agree to the terms and conditions
  </label>
</fieldset>
Legal disclaimers

Fully disabled checkbox

  • An input using disabled will not be focusable with the tab key
  • Arrow keys will still be able to browse disabled inputs
<fieldset>
  <legend>Choose the starcrossed NATO letters</legend>

  <input type="checkbox" id="romeoCheckbox" disabled checked>
  <label for="romeoCheckbox">Romeo</label>

  <input type="checkbox" id="julietCheckbox" disabled>
  <label for="julietCheckbox">Juliet</label>

</fieldset>
Choose the starcrossed NATO letters

Disabled and focusable checkbox

It’s possible to use aria-disabled="true" so screen reader users can focus the checkbox. Use preventDefault() to prevent the checkbox from being checked.

<fieldset>
  <legend>Choose your favorite cities</legend>

  <input type="checkbox" id="limaCheckbox" aria-disabled="true" checked>
  <label for="limaCheckbox">Lima</label>

  <input type="checkbox" id="quebecCheckbox" aria-disabled="true">
  <label for="quebecCheckbox">Quebec</label>

</fieldset>
Choose your favorite cities

When you can’t use semantic HTML

This custom checkbox requires extra attributes and event listeners.

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

Speciality checkboxes

Sometimes a design may call for a card type checkbox.

  • Its core should still be a semantic checkbox input
  • Use aria-describedby to read extra content after the the name, role and state
<ul class="cards">
  <li class="card interactive">
    <input type="checkbox"
           id="deltaCheckboxCard"
           aria-describedby="descriptionDelta" >
    <label for="deltaCheckboxCard">
      Delta
    </label>
    <div class="extended-description"
         id="descriptionDelta">
      Delta (prounounced: <strong>dell</strong>-tah)
      is the fourth letter of the NATO alphabet.
    </div>
  </li>
  <li class="card interactive">
    <input type="checkbox"
           id="echoCheckboxCard"
           aria-describedby="descriptionEcho" >
    <label for="echoCheckboxCard">Echo</label>
    <div class="extended-description"
         id="descriptionEcho">
      Echo (prounounced: <strong>eck</strong>-oh)
      is the fifth letter of the NATO alphabet.
    </div>
  </li>
</ul>
  • Delta (prounounced: dell-tah) is the fourth letter of the NATO alphabet.
  • Echo (prounounced: eck-oh) is the fifth letter of the NATO alphabet.

Developer notes

Name

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

Role

  • By default, semantic HTML checkbox inputs identify as a checkbox
  • Use role="checkbox" for custom elements

Group

  • Semantic HTML
    • <fieldset> wraps a checkbox group
    • <legend> describes the group’s purpose
    • Each <label> must include for="input-id" to be associated with its input
  • Custom elements
    • Use role="group" in the place 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 checkboxes
  • Custom element
    • Use aria-checked="true/false" to express state
    • Use aria-disabled="true" to declare inactive elements

Focus

  • Focus must be visible
  • Custom elements will require keyboard event listeners

Related checkbox entries