Onglets

Les onglets sont des affichages dynamiques de contenu dans une même zone de la page via un système d'étiquettes cliquables.

Règles d’implémentation pour l’accessibilité

  • L’élément qui sert de conteneur pour l’ensemble d’onglets a le rôle role="tablist".
  • Si l’élément tablist est orienté verticalement, sa propriété aria-orientation est définie sur vertical (la valeur par défaut de aria-orientation pour un élément de tablist est horizontal.).
  • Chaque élément qui sert d’onglet est contenu dans l’élément avec le rôle tablist et est :
    • un boutonbutton type="button";
    • avec un rôle role="tab" :
    • un attribut aria aria-controls qui fait référence au aria-labelledby du panneau qu’il contrôle ;
    • un rôle aria-selected défini sur true si l’onglet est actif, false sinon.
    • les boutons inactifs ne sont pas accessibles via la touche [tab] (attribut tabindex="-1", posé en javascript) mais par les touches “flèches de direction” du clavier.
  • Chaque élément qui contient le panneau de contenu de l’onglet
    • a le rôle role="tabpanel" ;
    • un attribut aria-labelledby dont la valeur fait référence à la valeur du aria-controls du bouton qui le contrôle 
    • une classe de style CSS qui le rend indisponible (déclaration display: none;) si le panneau n’est pas actif.

Visuel

Liste d'onglets activables au clavier

Sunt veniam ad reprehenderit exercitation non dolore exercitation labore deserunt laboris deserunt. Amet irure nulla eu nisi esse. Voluptate incididunt in Lorem cillum ut dolore enim qui magna. Dolore reprehenderit enim amet eu magna duis.

Aute dolore culpa minim id in est dolore officia enim adipisicing. Elit deserunt reprehenderit dolore aute duis ex. Culpa tempor esse non nostrud fugiat nisi deserunt magna amet.

Commodo ex id non consectetur laboris excepteur reprehenderit excepteur in velit veniam ex culpa. Occaecat excepteur in magna tempor. Et exercitation incididunt culpa reprehenderit irure.

Extraits de code

Code HTML

<div class="tabs">
  <h3>Liste d'onglets activables au clavier</h3>
  <div role="tablist" aria-labelledby="tablist-1" class="manual">
      <button id="tab-1" type="button" role="tab" aria-selected="true" aria-controls="tabpanel-1">
          <span>Premier onglet</span>
      </button>
      <button id="tab-2" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-2">
          <span>Deuxième onglet</span>
      </button>
      <button id="tab-3" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-3">
          <span>Troisième onglet</span>
      </button>
  </div>
  <div id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
      <p>
          Sunt veniam ad reprehenderit exercitation non dolore exercitation labore deserunt laboris deserunt.
          Amet irure nulla eu nisi esse. Voluptate incididunt in Lorem cillum ut dolore enim qui magna. Dolore
          reprehenderit enim amet eu magna duis.
      </p>
      <p>
          Aute dolore culpa minim id in est dolore officia enim adipisicing. Elit deserunt reprehenderit
          dolore aute duis ex. Culpa tempor esse non nostrud fugiat nisi deserunt magna amet.
      </p>
      <p>Commodo ex id non consectetur laboris excepteur reprehenderit excepteur in velit veniam ex culpa.
          Occaecat excepteur in magna tempor. Et exercitation incididunt culpa reprehenderit irure.</p>
  </div>
  <div id="tabpanel-2" role="tabpanel" aria-labelledby="tab-2" class="is-hidden">
      <p>
          Laboris esse id id consequat cillum eiusmod esse dolore. Dolor non ullamco aliqua cupidatat fugiat
          non. Amet enim aliquip veniam cillum consequat reprehenderit pariatur velit magna consectetur
          ullamco fugiat deserunt. Aliquip in pariatur veniam eiusmod magna laboris deserunt ea adipisicing
          proident laborum. Eiusmod consequat esse occaecat mollit. Commodo quis ea aute aliquip.
      </p>
      <p>Excepteur pariatur ut velit in do occaecat consectetur adipisicing labore ex. Reprehenderit qui non
          ipsum irure exercitation magna amet pariatur consectetur pariatur tempor ut ex. Sint dolore sit
          dolore ut eu sit dolor irure adipisicing pariatur elit dolore aliqua adipisicing. Non veniam magna
          eu irure ad non qui labore reprehenderit est. Occaecat veniam consequat velit Lorem ad aliqua
          excepteur labore mollit in.</p>
  </div>
  <div id="tabpanel-3" role="tabpanel" aria-labelledby="tab-3" class="is-hidden">
      <p>
          Ad laborum est minim est anim ea nisi sit. Duis fugiat mollit labore culpa duis. Sint Lorem mollit
          non ut sit reprehenderit proident cupidatat.
      </p>
      <p>Excepteur pariatur irure nulla anim laboris. Labore anim cupidatat veniam adipisicing cupidatat.
          Laboris ad culpa laboris culpa dolore nostrud laboris est. Eu ipsum laborum magna irure duis et in
          nulla et in velit est ut.</p>
  </div>
</div>

Code CSS

Pour adapter la couleur de la barre de navigation et des liens, modifier les codes couleurs dans la déclaration :root.

:root {
  --min-width: 640px;
  --max-height: 640px;
  --items-padding: 5px;
  --text-padding: 1em;

  --border-color: #b7b7b8;
  --background-color: #edeff3;
  --background-selected-color: #fbfcfe;
  --border-selected-color: #320075;
}

[role="tablist"] {
  min-width: var(--min-width);
}
[role="tablist"] button {
  padding: 0.25em;
}
[role="tab"],
[role="tab"]:focus,
[role="tab"]:hover {
  position: relative;
  z-index: 2;
  top: 2px;
  margin: 0;
  margin-top: 5px;
  border: 1px solid var(--border-color);
  border-bottom: 2px solid var(--border-color);
  border-radius: 5px 5px 0 0;
  overflow: visible;
  background: var(--background-color);
  outline: none;
  font-weight: bold;
}

[role="tab"]:focus,
[role="tab"]:hover {
  border-top-color: var(--border-selected-color);
  border-bottom-color: var(--background-selected-color);
  background: var(--background-selected-color);
  box-shadow: inset 0 0.25em 0.15em var(--border-selected-color);
}

[role="tab"][aria-selected="true"] {
  margin-top: 0;
  border-width: 2px;
  border-top-width: 6px;
  border-top-color: var(--border-selected-color);
  border-bottom-color: var(--background-selected-color);
  background: var(--background-selected-color);
  text-transform: uppercase;
}

[role="tab"][aria-selected="false"] {
  border-bottom: 1px solid var(--border-color);
}

[role="tabpanel"] {
  padding: var(--text-padding);
  border: 2px solid var(--border-color);
  border-radius: 0 5px 5px;
  background: var(--background-selected-color);
  min-height: 10em;
  min-width: var(--min-width);
  overflow: auto;
}

[role="tabpanel"].is-hidden {
  display: none;
}

[role="tabpanel"] p {
  margin: 0;
}
@media screen and (width <=768px) {
  [role="tab"] {
    font-size: 0.9em;
  }
}
@media screen and (width <=576px) {
  :root {
    --min-width: 500px;
  }
}

@media screen and (width <=576px) {
  :root {
    --min-width: 300px;
  }
  [role="tablist"] button span {
    display: none;
  }
}

Code javascript


"use strict";

class TabsManual {
  constructor(groupNode) {
    this.tablistNode = groupNode;

    this.tabs = [];

    this.firstTab = null;
    this.lastTab = null;

    this.tabs = Array.from(this.tablistNode.querySelectorAll("[role=tab]"));
    this.tabpanels = [];

    for (var i = 0; i < this.tabs.length; i += 1) {
      var tab = this.tabs[i];
      var tabpanel = document.getElementById(tab.getAttribute("aria-controls"));

      tab.tabIndex = -1;
      tab.setAttribute("aria-selected", "false");
      this.tabpanels.push(tabpanel);

      tab.addEventListener("keydown", this.onKeydown.bind(this));
      tab.addEventListener("click", this.onClick.bind(this));

      if (!this.firstTab) {
        this.firstTab = tab;
      }
      this.lastTab = tab;
    }

    this.setSelectedTab(this.firstTab);
  }

  setSelectedTab(currentTab) {
    for (var i = 0; i < this.tabs.length; i += 1) {
      var tab = this.tabs[i];
      if (currentTab === tab) {
        tab.setAttribute("aria-selected", "true");
        tab.removeAttribute("tabindex");
        this.tabpanels[i].classList.remove("is-hidden");
      } else {
        tab.setAttribute("aria-selected", "false");
        tab.tabIndex = -1;
        this.tabpanels[i].classList.add("is-hidden");
      }
    }
  }

  moveFocusToTab(currentTab) {
    currentTab.focus();
  }

  moveFocusToPreviousTab(currentTab) {
    var index;

    if (currentTab === this.firstTab) {
      this.moveFocusToTab(this.lastTab);
    } else {
      index = this.tabs.indexOf(currentTab);
      this.moveFocusToTab(this.tabs[index - 1]);
    }
  }

  moveFocusToNextTab(currentTab) {
    var index;

    if (currentTab === this.lastTab) {
      this.moveFocusToTab(this.firstTab);
    } else {
      index = this.tabs.indexOf(currentTab);
      this.moveFocusToTab(this.tabs[index + 1]);
    }
  }

  /* EVENT HANDLERS */

  onKeydown(event) {
    var tgt = event.currentTarget,
      flag = false;

    switch (event.key) {
      case "ArrowLeft":
        this.moveFocusToPreviousTab(tgt);
        flag = true;
        break;

      case "ArrowRight":
        this.moveFocusToNextTab(tgt);
        flag = true;
        break;

      case "Home":
        this.moveFocusToTab(this.firstTab);
        flag = true;
        break;

      case "End":
        this.moveFocusToTab(this.lastTab);
        flag = true;
        break;

      default:
        break;
    }

    if (flag) {
      event.stopPropagation();
      event.preventDefault();
    }
  }

  // Since this example uses buttons for the tabs, the click onr also is activated
  // with the space and enter keys
  onClick(event) {
    this.setSelectedTab(event.currentTarget);
  }
}

// Initialize tablist

window.addEventListener("load", function () {
  var tablists = document.querySelectorAll("[role=tablist].manual");
  for (var i = 0; i < tablists.length; i++) {
    new TabsManual(tablists[i]);
  }
});