Normes · ARIA

Rôle Structure du document

tabpanel

Désigne le panneau de contenu associé à un onglet. Chaque tabpanel est nommé par son onglet via aria-labelledby ; l'onglet référence le panneau via aria-controls. Affichez un seul panneau à la fois ; masquez les autres avec l'attribut hidden.

Quand l’utiliser

Sur le conteneur qui détient le contenu d’un onglet. Associez chaque tabpanel à son onglet via aria-labelledby (pointant vers l’identifiant de l’onglet). L’onglet, à son tour, pointe vers le panneau avec aria-controls. Masquez les panneaux inactifs avec l’attribut hidden — pas seulement display: none via CSS — afin que l’arbre d’accessibilité reflète l’état visuel.

Si le panneau contient du contenu interactif (un formulaire, une liste de liens), vous pouvez le rendre focalisable avec tabindex="0". Ainsi, après l’activation d’un onglet, la prochaine touche Tab atterrit à l’intérieur du panneau.

Si le panneau contient une seule région focalisable — par exemple un grand titre suivi d’un contenu — tabindex="0" sur le panneau est suffisant. Si le panneau est rempli de contrôles focalisables, l’utilisateur y accèdera directement avec Tab et le tabindex est facultatif.

Erreurs courantes

  • Tabpanel masqué via CSS mais pas via l’attribut hidden. Les lecteurs d’écran peuvent encore exposer son contenu.
  • Tabpanel sans aria-labelledby — annoncé simplement comme « panneau d’onglet » sans nom.
  • L’onglet pointe vers un identifiant de tabpanel via aria-controls mais le panneau ne pointe pas en retour via aria-labelledby. L’association doit être réciproque.
  • Tous les tabpanels sont dans le DOM avec display: none commuté dynamiquement, mais sans attribut hidden. Les auditeurs signalent l’incohérence.
  • role="tabpanel" appliqué à un panneau qui n’est PAS associé à un role="tab" — tabpanel orphelin.

Exemple

<div role="tablist" aria-label="Settings">
  <button role="tab" id="t-account" aria-selected="true"  aria-controls="p-account" tabindex="0">Account</button>
  <button role="tab" id="t-billing" aria-selected="false" aria-controls="p-billing" tabindex="-1">Billing</button>
</div>

<section role="tabpanel" id="p-account" aria-labelledby="t-account" tabindex="0">
  <h2>Account</h2>
  <p>…</p>
</section>
<section role="tabpanel" id="p-billing" aria-labelledby="t-billing" tabindex="0" hidden>
  <h2>Billing</h2>
  <p>…</p>
</section>