Skip to Content

Chapitre 4.3 — Bien utiliser tabindex

⏱️ TL;DR — L’attribut tabindex contrôle si — et comment — un élément reçoit le focus. Trois cas seulement à retenir : tabindex="0" ajoute l’élément à l’ordre de tabulation naturel (utile pour un composant custom qui doit être focusable) ; tabindex="-1" le rend focusable par JavaScript (element.focus()) mais pas via Tab (utile pour déplacer le focus par programme) ; et toute valeur positive (tabindex="1", 2…) est un anti-pattern qui casse l’ordre du DOM. Règle d’or : n’ajoute tabindex que si tu as une vraie raison, et jamais de valeur positive.

🎯 Objectifs

  • Comprendre les trois usages de tabindex : 0, -1, positif.
  • Savoir quand rendre un élément focusable — et quand surtout ne pas le faire.
  • Comprendre pourquoi les valeurs positives sont à bannir.
  • Découvrir le principe du roving tabindex (détaillé en Partie 10).

Les trois valeurs de tabindex

tabindex prend une valeur numérique, mais seuls trois comportements existent réellement.

ValeurFocusable au Tab ?Focusable en JS (.focus()) ?Usage
tabindex="0"✅ oui, à sa place dans le DOM✅ ouiRendre focusable un élément non interactif natif (rare).
tabindex="-1"❌ non✅ ouiCible de focus programmatique (modale, message, section).
tabindex="1" et +✅ mais hors ordre DOM✅ ouiÀ bannir — casse le parcours du focus.

tabindex="0" — entrer dans l’ordre naturel

tabindex="0" place l’élément dans l’ordre de tabulation à la position que lui donne le DOM, comme s’il était nativement interactif. Tu n’en as besoin que pour un élément qui n’est pas déjà focusable mais qui doit l’être — typiquement un composant custom.

<!-- ✅ Un composant custom qui doit être focusable (faute de mieux qu'un élément natif) --> <div role="button" tabindex="0" onclick="basculer()">Options avancées</div>

Mais attention : dès que tu écris ça, souviens-toi du Chapitre 4.1 — tu dois aussi gérer Entrée/Espace et le rôle à la main. 90 % du temps, un <button> natif est le bon choix et rend ce tabindex="0" inutile.

tabindex="-1" — focusable, mais pas par Tab

tabindex="-1" retire l’élément de l’ordre de tabulation (Tab le saute) tout en le rendant ciblable par JavaScript via element.focus(). C’est l’outil clé du Chapitre 4.4 : déplacer le focus sur une modale qu’on vient d’ouvrir, sur un titre après un changement de route, sur un message d’erreur.

<!-- ✅ On ne veut pas que Tab s'arrête ici, mais on veut pouvoir y ENVOYER le focus en JS --> <div id="dialogue" role="dialog" tabindex="-1" aria-modal="true"> <h2>Confirmer la suppression</h2> </div>
// À l'ouverture, on déplace le focus sur le conteneur du dialogue document.getElementById("dialogue").focus();

Les valeurs positives — l’anti-pattern

tabindex="1", tabindex="2"… forcent un ordre de tabulation prioritaire, indépendant du DOM. Le navigateur visite d’abord tous les éléments à tabindex positif (dans l’ordre croissant), puis les éléments dans l’ordre normal. Résultat : un ordre de focus imprévisible, ingérable, qui se désynchronise dès qu’on ajoute un champ.

<!-- ❌ Ordre de focus artificiel et fragile : maintenance cauchemardesque --> <input tabindex="3" name="email"> <input tabindex="1" name="nom"> <input tabindex="2" name="prenom">
<!-- ✅ Aucun tabindex : l'ordre du focus suit l'ordre du DOM, logique et robuste --> <input name="nom"> <input name="prenom"> <input name="email">

Le bon ordre de focus s’obtient en ordonnant correctement ton HTML, pas en numérotant les champs. Si l’ordre te déplaît, corrige le DOM — voir Chapitre 4.2.

💡 Réflexe — Retiens la formule : 0 pour ajouter, -1 pour cibler en JS, positif jamais. Et avant même d’écrire un tabindex, pose-toi la vraie question : « Est-ce que je ne devrais pas simplement utiliser un <button>, un <a> ou un <input> natif ? » La plupart des tabindex="0" sont le symptôme d’une <div> qui aurait dû être un vrai élément interactif.

Rendre focusable… ou pas

Deux erreurs symétriques, aussi fréquentes l’une que l’autre :

  • Ne pas rendre focusable ce qui devrait l’être : un contrôle custom (<div> faisant office de bouton/onglet/case) sans tabindex → l’utilisateur clavier ne l’atteint jamais. Solution : élément natif, ou à défaut tabindex="0" + rôle + gestion des touches.
  • Rendre focusable ce qui ne devrait pas l’être : coller tabindex="0" sur des titres, des paragraphes, des <div> de mise en page → l’utilisateur clavier subit une avalanche d’arrêts inutiles sur du contenu non interactif. Le texte se lit avec le lecteur d’écran, il ne se tabule pas.

La cible se résume à : exactement les éléments interactifs sont dans l’ordre de tabulation — ni plus, ni moins.

Aperçu : le roving tabindex

Un motif que tu croiseras dans les composants riches (menus, listes d’onglets, grilles) : le roving tabindex (« tabindex baladeur »). Principe : dans un groupe d’éléments qui se parcourt aux flèches (et non au Tab), un seul élément porte tabindex="0" à un instant donné — celui qui a « le tour » — et tous les autres portent tabindex="-1". Quand l’utilisateur presse une flèche, on déplace le tabindex="0" sur l’élément voisin (et on lui donne le focus).

Effet : Tab entre et sort du composant comme d’un tout (un seul arrêt), et les flèches naviguent à l’intérieur. C’est exactement la distinction « entre / dans » du Chapitre 4.1. On l’implémente en détail avec les patterns APG en Partie 10 ; retiens juste le principe ici.

🧭 Sur A11yLearn — Sur A11yLearn, la barre d’onglets d’un cours (« Aperçu », « Leçons », « Ressources », « Discussion ») utilise le roving tabindex. Avant, chaque onglet était un lien : Tab s’arrêtait quatre fois pour traverser la barre. Désormais, un seul onglet a tabindex="0", les trois autres tabindex="-1" : Tab fait un arrêt sur la barre, et les flèches passent d’un onglet à l’autre — le comportement attendu d’un jeu d’onglets, et celui que décrit l’APG.

✏️ Exercices

Exercice 1 — Corrige les tabindex. Un développeur a « forcé l’ordre » d’un formulaire. Explique le problème et propose la version correcte.

<input tabindex="2" name="mot_de_passe" type="password"> <input tabindex="1" name="identifiant"> <button tabindex="3" type="submit">Se connecter</button>

✅ Solution

Les tabindex positifs créent un ordre artificiel, fragile et prioritaire sur le reste de la page. On les supprime et on ordonne le HTML logiquement :

<input name="identifiant"> <input name="mot_de_passe" type="password"> <button type="submit">Se connecter</button>

L’ordre du focus suit alors le DOM (identifiant → mot de passe → bouton), sans aucun tabindex. Robuste et sans maintenance.

Exercice 2 — Quel tabindex ? Tu ouvres une modale par programme et tu veux y envoyer le focus, mais sans que Tab s’arrête sur son conteneur en temps normal. Quelle valeur de tabindex mets-tu sur le conteneur, et pourquoi ?

✅ Solution

tabindex="-1". Il rend le conteneur ciblable en JavaScript (conteneur.focus()) pour y déplacer le focus à l’ouverture, sans l’insérer dans l’ordre de tabulation Tab. C’est précisément le cas d’usage du -1 : une cible de focus programmatique. On verra la mécanique complète au Chapitre 4.4.

🧠 Quiz de révision

1. Que fait tabindex=“0” ?

Il ajoute l’élément à l’ordre de tabulation naturel, à la position que lui donne le DOM — comme s’il était nativement interactif. Utile pour rendre focusable un élément custom qui ne l’est pas nativement (rare : préfère un élément natif).

2. Quelle est la différence entre tabindex=“-1” et tabindex=“0” ?

tabindex="0" rend l’élément focusable au Tab ET en JS. tabindex="-1" le rend focusable uniquement en JS (.focus()), mais Tab le saute. Le -1 sert à créer des cibles de focus programmatiques (modale, message, section).

3. Pourquoi ne jamais utiliser de tabindex positif ?

Parce qu’il crée un ordre de tabulation artificiel et prioritaire sur l’ordre du DOM : le focus visite d’abord tous les éléments à valeur positive, puis le reste. C’est imprévisible, ingérable et ça se casse au moindre ajout. Le bon ordre s’obtient en ordonnant le HTML.

4. Faut-il mettre tabindex=“0” sur un titre pour qu’il soit lu ?

Non. Un titre se lit via le lecteur d’écran et la navigation par titres ; il n’a pas à être dans l’ordre de tabulation. Mettre tabindex="0" sur du contenu non interactif noie l’utilisateur clavier sous des arrêts inutiles.

5. En une phrase, qu’est-ce que le roving tabindex ?

Une technique où, dans un groupe navigable aux flèches, un seul élément porte tabindex="0" (les autres tabindex="-1") : Tab entre et sort du composant comme d’un tout, et les flèches naviguent à l’intérieur. Détaillé en Partie 10.


Chapitre suivant : Gérer le focus en JS — déplacer le focus après une action, le focus trap des modales, et les liens d’évitement.

Last updated on