Le symptôme remonté par un testeur au clavier était précis : « après avoir fermé la popup de newsletter, j’appuie sur Tab et je me retrouve tout en haut de la page, avant le logo ». Un défaut discret à la souris, où l’on ne remarque jamais où atterrit le focus, mais franchement pénible au clavier, puisqu’il faut alors retraverser tout le menu de navigation pour revenir là où on se trouvait avant l’ouverture de la fenêtre.
Ce défaut porte un nom dans les référentiels d’accessibilité : la perte de focus, ou focus mal repositionné. Il touche presque toutes les fenêtres modales codées sans suivre le motif ARIA officiel, et se corrige toujours de la même manière une fois la cause identifiée.
Symptôme observé pas à pas
En reproduisant le scénario : ouverture de la modale par un clic sur un bouton « S’inscrire à la newsletter », fermeture par la croix ou par la touche Échap, puis appui sur Tab. Le focus se retrouve tantôt sur le premier lien du menu, tantôt totalement invisible, comme si le navigateur avait remis le focus sur <body>, qui n’est normalement pas un élément focusable.
Diagnostic : où va vraiment le focus quand un élément disparaît

La règle du navigateur est simple et rarement documentée dans les tutoriels de modales : quand l’élément qui a le focus est retiré du DOM (ou masqué avec display: none), le focus retombe automatiquement sur <body>. Si la fenêtre modale avait le focus au moment de sa fermeture — ce qui est le cas normal, puisque le focus doit être piégé à l’intérieur pendant qu’elle est ouverte — et que le code de fermeture se contente de masquer la modale sans jamais restaurer explicitement le focus ailleurs, alors le focus part sur <body>, d’où le comportement observé au Tab suivant, qui repart du tout début du DOM.
// Code fautif : ferme la modale sans restaurer le focus
function fermerModale() {
modale.classList.add('masquee');
modale.setAttribute('aria-hidden', 'true');
}
Le correctif : mémoriser puis restaurer le déclencheur
La correction demande de conserver une référence à l’élément qui avait le focus avant l’ouverture de la modale — presque toujours le bouton qui l’a déclenchée — et de lui redonner explicitement le focus à la fermeture :
let declencheur = null;
function ouvrirModale(bouton) {
declencheur = bouton;
modale.classList.remove('masquee');
modale.setAttribute('aria-hidden', 'false');
modale.querySelector('button, [href], input').focus();
}
function fermerModale() {
modale.classList.add('masquee');
modale.setAttribute('aria-hidden', 'true');
if (declencheur) {
declencheur.focus();
}
}
Ce simple appel à declencheur.focus() ramène l’utilisateur exactement là où il se trouvait avant l’ouverture, ce qui correspond à ce qu’un utilisateur voyant vit implicitement : la modale disparaît, l’attention visuelle revient naturellement à l’endroit où elle se trouvait avant l’interruption.
Le piège de la fermeture par Échap
Un oubli fréquent : la fonction de fermeture appelée au clic sur la croix restaure bien le focus, mais celle appelée sur la touche Échap est une fonction différente, ajoutée plus tard par un autre développeur, qui ne fait pas le même appel. Vérifier que tous les chemins de fermeture — croix, Échap, clic en dehors de la modale — passent par la même fonction unique évite ce genre d’écart silencieux.
Vérification
Le test de non-régression tient en quatre étapes reproductibles : ouvrir la modale au clavier, la fermer par chacun des trois moyens disponibles, et vérifier à chaque fois qu’un appui sur Tab suivant atterrit sur l’élément qui suit logiquement le bouton d’ouverture dans la page, jamais sur <body> ni sur le tout premier élément focusable du document.
En résumé
Une fenêtre modale bien fermée doit rendre le focus exactement là où il se trouvait avant son ouverture. Ce comportement ne s’obtient jamais par hasard : il demande de mémoriser explicitement l’élément déclencheur à l’ouverture et de lui redonner le focus à la fermeture, sur chacun des chemins qui permettent de fermer la fenêtre.