Aller au contenu principal
Technique19 février 20268 min

Tabindex : bonnes pratiques et pièges à éviter

En Bref : L'essentiel à retenir

  • tabindex="0" ajoute un élément à l'ordre de tabulation naturel, tabindex="-1" le rend focusable uniquement par JavaScript.
  • Les valeurs positives de tabindex (1, 2, 3...) sont à proscrire car elles perturbent l'ordre naturel de navigation.
  • Les éléments interactifs natifs (button, a, input) sont focusables par défaut et n'ont pas besoin de tabindex.
  • Le roving tabindex est une technique pour gérer le focus dans les composants complexes comme les onglets ou menus.
ClavierHTMLAccessibilitéNavigation

L'attribut tabindex contrôle si et comment un élément peut recevoir le focus clavier. Bien utilisé, il améliore l'accessibilité. Mal utilisé, il peut rendre la navigation complètement chaotique. Ce guide vous explique comment maîtriser cet attribut essentiel.

Les trois valeurs de tabindex

tabindex="0" : Ajouter à l'ordre de tabulation

Un élément avec tabindex="0" devient focusable et s'insère dans l'ordre naturel de tabulation (défini par l'ordre du DOM).

CODE
<!-- Ce div devient focusable au clavier -->
<div tabindex="0" role="button" onclick="action()">
  Élément interactif custom
</div>

Cas d'usage :

  • Rendre focusable un élément non interactif
  • Permettre le focus sur une région de contenu (tabpanel, dialog)

tabindex="-1" : Focusable par script uniquement

Un élément avec tabindex="-1" peut recevoir le focus via JavaScript (élément.focus()) mais n'est pas accessible via la touche Tab.

CODE
<!-- Focusable par script, pas par Tab -->
<div tabindex="-1" id="zone-erreur">
  Message d'erreur qui recevra le focus programmatiquement
</div>
CODE
// Focus programmatique
document.getElementById('zone-erreur').focus();

Cas d'usage :

  • Éléments qui doivent recevoir le focus après une action (messages d'erreur, modales)
  • Éléments dans un composant avec roving tabindex (onglets inactifs)
  • Zones de contenu non interactives qui doivent être lues par les lecteurs d'écran

tabindex > 0 : À éviter absolument

Une valeur positive (1, 2, 3, etc.) place l'élément avant tous les éléments avec tabindex="0" dans l'ordre de tabulation.

CODE
<!-- NE FAITES PAS CECI -->
<button tabindex="3">Troisième focus</button>
<button tabindex="1">Premier focus</button>
<button tabindex="2">Deuxième focus</button>

[!NOTE] Les valeurs positives de tabindex sont considérées comme une mauvaise pratique par le W3C et les experts en accessibilité. Elles créent un ordre de navigation artificiel déconnecté du DOM, source de confusion pour les utilisateurs.

Les éléments nativement focusables

Ces éléments HTML sont focusables par défaut, sans tabindex :

élémentCondition
<a>Avec attribut href
<button>Non désactivé
<input>Non désactivé, non type="hidden"
<select>Non désactivé
<textarea>Non désactivé
<details>L'élément <summary> est focusable
<iframe>Toujours focusable

N'ajoutez pas tabindex="0" à ces éléments, c'est inutile :

CODE
<!-- Inutile : le bouton est déjà focusable -->
<button tabindex="0">Cliquer</button>

<!-- Correct -->
<button>Cliquer</button>

Quand utiliser tabindex="0"

Éléments interactifs custom

Quand vous créez un composant interactif avec un élément non focusable :

CODE
<div
  role="button"
  tabindex="0"
  onclick="action()"
  onkeydown="if(event.key==='Enter'||event.key===' ')action()"
>
  Bouton personnalisé
</div>

[!TIP] Privilégiez toujours l'élément natif quand c'est possible. <button> est préférable à <div role="button" tabindex="0">.

Conteneurs de contenu non interactif

Pour les zones qui doivent être accessibles aux lecteurs d'écran via Tab (comme les tabpanels) :

CODE
<div role="tabpanel" tabindex="0" aria-labelledby="tab-1">
  Contenu du panneau sans éléments interactifs.
  Le tabindex permet de naviguer jusqu'ici avec Tab.
</div>

Éléments avec rôle de landmark

Certains landmarks bénéficient d'un tabindex pour être directement accessibles :

CODE
<main tabindex="-1" id="contenu-principal">
  <!-- Permet le focus après un "skip to main content" -->
</main>

Quand utiliser tabindex="-1"

Gestion du focus programmatique

Après une action, déplacer le focus vers un élément spécifique :

CODE
<div id="notification" tabindex="-1" role="alert">
  Votre message a été envoyé avec succès.
</div>
CODE
function afficherNotification(message) {
  const notif = document.getElementById('notification');
  notif.textContent = message;
  notif.focus();
}

Éléments temporairement inactifs dans un widget

Dans les onglets, menus, ou autres composants avec roving tabindex :

CODE
<div role="tablist">
  <button role="tab" aria-selected="true" tabindex="0">Actif</button>
  <button role="tab" aria-selected="false" tabindex="-1">Inactif</button>
  <button role="tab" aria-selected="false" tabindex="-1">Inactif</button>
</div>

Empêcher le focus sur un élément temporairement

CODE
<!-- Pendant le chargement, le bouton est ignore par Tab -->
<button tabindex="-1" disabled>Chargement...</button>

<!-- Une fois prêt, il redevient focusable -->
<button tabindex="0">Envoyer</button>

La technique du roving tabindex

Le "roving tabindex" est un pattern pour gérer le focus dans les composants complexes comme les menus, onglets, ou listes.

Principe

  • Un seul élément du groupe a tabindex="0" (celui qui est actif/sélectionné)
  • Tous les autres ont tabindex="-1"
  • Les flèches déplacent le focus et mettent à jour les tabindex

Exemple : système d'onglets

CODE
<div role="tablist">
  <button role="tab" aria-selected="true" tabindex="0" id="tab-1">
    Onglet 1
  </button>
  <button role="tab" aria-selected="false" tabindex="-1" id="tab-2">
    Onglet 2
  </button>
  <button role="tab" aria-selected="false" tabindex="-1" id="tab-3">
    Onglet 3
  </button>
</div>
CODE
const tabs = document.querySelectorAll('[role="tab"]');
let currentIndex = 0;

tabs.forEach((tab, index) => {
  tab.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowRight') {
      e.preventDefault();
      goToTab((currentIndex + 1) % tabs.length);
    }
    if (e.key === 'ArrowLeft') {
      e.preventDefault();
      goToTab((currentIndex - 1 + tabs.length) % tabs.length);
    }
  });
});

function goToTab(newIndex) {
  // Ancien onglet
  tabs[currentIndex].setAttribute('tabindex', '-1');
  tabs[currentIndex].setAttribute('aria-selected', 'false');

  // Nouvel onglet
  currentIndex = newIndex;
  tabs[currentIndex].setAttribute('tabindex', '0');
  tabs[currentIndex].setAttribute('aria-selected', 'true');
  tabs[currentIndex].focus();
}

Avantages du roving tabindex

  • Un seul Tab suffit pour entrer/sortir du composant
  • Flèches pour naviguer à l'intérieur
  • Expérience prévisible : conforme aux patterns ARIA

Erreurs courantes avec tabindex

1. tabindex positif

CODE
<!-- INCORRECT : crée un ordre de navigation chaotique -->
<div tabindex="1">Premier</div>
<div tabindex="3">Troisième</div>
<div tabindex="2">Deuxième</div>

Solution : Réorganisez le DOM pour refléter l'ordre de navigation souhaité.

2. tabindex="0" sur éléments non interactifs

CODE
<!-- INCORRECT : le paragraphe ne devrait pas être dans l'ordre de tab -->
<p tabindex="0">Un simple texte.</p>

Ajouter un paragraphe à l'ordre de tabulation oblige les utilisateurs clavier à tabuler sur des éléments où ils ne peuvent rien faire.

Solution : Ne rendez focusables que les éléments interactifs ou les régions importantes.

3. Oublier de gérer le clavier

CODE
<!-- INCORRECT : focusable mais pas actionnable au clavier -->
<div tabindex="0" onclick="action()">
  Cliquez-moi
</div>

Solution : Ajoutez la gestion du clavier ou utilisez un <button>.

CODE
<div
  tabindex="0"
  role="button"
  onclick="action()"
  onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();action()}"
>
  Cliquez-moi
</div>

4. tabindex="-1" pour "cacher" un élément

CODE
<!-- INCORRECT : l'élément reste visible et cliquable -->
<button tabindex="-1">Invisible au clavier mais visible</button>

Solution : utilisez disabled, hidden, ou aria-hidden="true" selon le besoin.

5. tabindex sur tous les éléments d'une page

Certains croient (à tort) que tabindex="0" améliore l'accessibilité en général.

Réalité : Cela force les utilisateurs à tabuler sur chaque élément, ralentissant considérablement la navigation.

CSS et ordre visuel vs ordre du DOM

Attention : CSS (flex order, grid, position) peut changer l'ordre visuel sans modifier l'ordre du DOM. Cela crée une déconnexion entre ce que voit l'utilisateur et l'ordre de tabulation.

CODE
<div style="display: flex;">
  <button style="order: 2">Visuellement second</button>
  <button style="order: 1">Visuellement premier</button>
</div>
<!-- Le focus ira d'abord sur "Visuellement second" ! -->

Solution : Alignez l'ordre du DOM avec l'ordre visuel, ou utilisez le roving tabindex si nécessaire.

Test de l'ordre de tabulation

Test manuel

  1. Placez votre focus en haut de la page
  2. Appuyez sur Tab répétitivement
  3. Vérifiez que :
    • L'ordre est logique et prévisible
    • Vous atteignez tous les éléments interactifs
    • Vous ne vous retrouvez pas "piégé"
    • Le focus ne "saute" pas de manière inattendue

Test avec l'inspecteur d'accessibilité

Les DevTools Chrome permettent de visualiser l'ordre de tabulation dans le panneau Accessibility.

Test automatisé

Notre outil d'audit RGAA détecte les tabindex positifs et d'autres problèmes de navigation clavier.

Résumé des bonnes pratiques

ValeurUtilisationÀ éviter
tabindex="0"Éléments custom interactifs, tabpanelsÉléments non interactifs, éléments déjà focusables
tabindex="-1"Focus programmatique, roving tabindexCacher visuellement un élément
tabindex > 0JamaisToujours

Conclusion

tabindex est un outil puissant mais qui doit être utilisé avec parcimonie. Dans la majorité des cas, les éléments HTML natifs fournissent déjà le comportement de focus nécessaire. N'ajoutez tabindex que lorsque vous avez une raison spécifique de le faire.

Retenez ces trois règles :

  1. Utilisez les éléments natifs quand c'est possible
  2. N'utilisez jamais de valeurs positives
  3. Testez la navigation clavier après toute modification

En suivant ces bonnes pratiques, vous garantissez une navigation clavier fluide et prévisible pour tous vos utilisateurs.

Votre site est-il conforme ?

Ne prenez pas de risques avec l'accessibilité. Lancez un audit complet de votre site en quelques minutes et obtenez un rapport détaillé des corrections à apporter.