Les listbox avec cases à cocher

Thématiques associées :
  • Composant

Introduction

Dans cet exemple, nous repartons de l’exemple sur les listbox auquel nous ajoutons des cases à cocher. Nous obtiendrons un composant qui nous permettra de sélectionner un élément parmi une liste de choix, comme une listbox classique, mais qui permettra également de cocher certains éléments. Un composant qu’on pourrait typiquement trouver dans un webmail.

Mise en garde

Bien que des progrès soient réalisés à chaque nouvelle version, le support d’ARIA est encore partiel pour l’ensemble des lecteurs d’écran. Son utilisation doit être conditionnée par des tests de compatibilité sur l’environnement cible (couple navigateur/lecteur d’écran).

Mise en place

Code HTML

Le code reprend celui de l’exemple sur les listbox auquel nous ajoutons l’information concernant l’état coché / non coché. Pour cela nous utilisons l’attribut aria-checked.


  <ul role="listbox" tabindex="0" aria-label="liste des emails">
      <li tabindex="-1" role="option" aria-checked="false">Informations importantes concernant votre compte</li>
      …
  </ul>

Pour afficher à l’écran l’état « coché » de l’élément, on pourrait très bien le faire via CSS, en affichant un pictogramme juste avant les éléments ayant un attribut aria-checked="true".

Dans cet exemple, nous allons insérer de vraies cases à cocher à l’intérieur des options. Celles-ci ne seront pas vocalisées par le lecteur d’écran grâce à la présence du role="option" (pour le lecteur d’écran, ce sera une option et peu importe ce qu’on met à l’intérieur).


  <ul role="listbox" tabindex="0" aria-label="liste des emails">
      <li tabindex="-1" role="option" aria-checked="false">
          <input tabindex="-1" type="checkbox">Informations importantes concernant votre compte
      </li>
      …
  </ul>

Ne pas oublier d’ajouter un attribut tabindex="-1" pour empêcher le focus sur les cases à cocher.

Si nous voulons des cases à cocher un peu plus jolies, on peut utiliser celles de la librairie Boosted par exemple.
Dans ce cas, il faut ajouter également une balise label.


  <ul role="listbox" tabindex="0" aria-label="liste des emails">
      <li tabindex="-1" role="option" aria-checked="false">
        <div class="form-check">
          <input tabindex="-1" id="check1" class="form-check-input" type="checkbox"><label for="check1" class="form-check-label"></label>
          Informations importantes concernant votre compte
        </div>
      </li>
      …
  </ul>

À noter que la balise label reste vide ici. En effet dans ce composant, on ne souhaite pas que la case à cocher soit sélectionnée si on clique sur le texte affiché dans la liste.

Interactions

Pour gérer l’interaction à la souris, il suffit de modifier la valeur de l’attribut aria-checked lorsqu’une case à cocher est cliquée.


document.querySelectorAll("[type=checkbox]").forEach(checkbox =>{
  checkbox.addEventListener("click",function(e){
      if(this.checked){
          this.parentElement.parentElement.setAttribute("aria-checked", "true");
      }
      else{
          this.parentElement.parentElement.setAttribute("aria-checked", "false");
      }
      e.stopPropagation();
  })
})
 

Il ne reste plus qu’à gérer l’interaction au clavier. Un élément doit pouvoir être coché ou décoché à l’aide de la barre espace. On insère ce comportement à la suite du code qui gère déjà les flèches du clavier (cf. exemple sur les listbox).


  document.getElementById("exempleCheckbox").addEventListener("keydown", function (e) {
    let currentItem = this.querySelector("[aria-selected=true]");
    switch(e.keyCode){
        case 38: // Up arrow
            if(currentItem.previousElementSibling !== null){
                currentItem.setAttribute("aria-selected","false");
                currentItem.previousElementSibling.setAttribute("aria-selected", "true");
                currentItem.previousElementSibling.focus();
                currentItem.previousElementSibling.classList.add('active');
            }
            e.preventDefault();
            break;
        case 40: // Down arrow
            if(currentItem.nextElementSibling !== null){
                currentItem.setAttribute("aria-selected","false");
                currentItem.nextElementSibling.setAttribute("aria-selected","true");
                currentItem.nextElementSibling.focus();
                currentItem.nextElementSibling.classList.add('active');
            }
            e.preventDefault();
            break;
case 32: // Space if (currentItem.getAttribute("aria-checked") === "true") { currentItem.setAttribute("aria-checked", "false"); currentItem.querySelector("input[type=checkbox]").checked = false; } else { currentItem.setAttribute("aria-checked", "true"); currentItem.firstElementChild.setAttribute("aria-checked", "true"); currentItem.querySelector("input[type=checkbox]").checked = true;; } e.preventDefault(); break;
} });

Exemple

Liste des emails

Place aux tests

Utilisation à la souris : on peut sélectionner une option en cliquant sur le texte. On peut cocher ou décocher une option en cliquant sur les cases à cocher.

Utilisation au clavier : on peut sélectionner une option à l’aide des flèches du clavier haut ou bas. On peut cocher ou décocher une option à l’aide de la barre espace.

Utilisation avec un lecteur d’écran : mêmes raccourcis clavier (haut, bas et barre espace). Pour chaque élément, le lecteur d’écran nous donne l’information si celui-ci est sélectionné et s’il est coché ou non.

Exemple webmail

Voici une maquette statique qui met en œuvre le composant listbox de cet exemple et celui de l’exemple sur les listbox classiques.

Ouvrir le webmail

Liens

Plus d’infos sur ARIA et les listbox :