La modale
Une fenêtre qui interrompt tout doit rendre ce qu'elle prend : le focus, le clavier, l'annonce au lecteur d'écran. L'élément natif <dialog> donne les quatre. Démo, code, critères RGAA.
5 critères RGAA en jeu
Essayez-la
Ouvrez-la, puis n’utilisez que le clavier : Tab circule entre les deux boutons sans jamais sortir de la fenêtre, Échap ferme et rend le focus au bouton d’ouverture. C’est tout le contrat d’une modale, et il tient en une phrase : ce qu’elle prend, elle le rend.
Cette démo existe aussi en page autonome — ouvrez-la avec notre extension pour vérifier ce qu’elle déclare.
L’erreur courante
La modale bricolée, c’est deux div : un voile sombre, une boîte par-dessus,
un peu de JavaScript pour les afficher.
<!-- À ne pas faire : rien ici ne dit « dialogue » à personne -->
<div class="voile">
<div class="boite">
<h2>Retirer la page de l'audit ?</h2>
…
</div>
</div> Visuellement, tout y est. Au clavier et au lecteur d’écran, rien n’y est :
- Tab continue de circuler dans la page derrière le voile — on navigue dans un contenu qu'on ne voit plus ;
- Échap ne ferme rien ;
- le lecteur d’écran n’annonce pas qu’un dialogue s’est ouvert, ni son titre ;
- à la fermeture, le focus reste perdu là où il était.
Chacun de ces quatre manques se répare à la main — piège de focus, écouteur
clavier, role="dialog", mémorisation de l’élément déclencheur — et chaque
réparation est un endroit où se tromper. Le HTML a un élément qui donne les
quatre d’un coup.
Le code, pas à pas
1. L’élément <dialog> et showModal()
<button type="button" data-ouvre="confirmation">
Retirer la page de l'audit
</button>
<dialog id="confirmation">
<h2>Retirer la page de l'audit ?</h2>
<p>
Ses vérifications déjà tranchées seront conservées, mais la page ne
comptera plus dans le taux de conformité.
</p>
</dialog> const dialogue = document.getElementById('confirmation');
document
.querySelector('[data-ouvre="confirmation"]')
.addEventListener('click', () => dialogue.showModal()); C’est showModal() — pas show() — qui fait la modale. Le navigateur prend
tout en charge : le focus entre dans la fenêtre et n’en sort plus, Échap ferme, le reste de la page devient inerte — invisible aux technologies d’assistance et inatteignable au clavier — et à la
fermeture, le focus revient à l’élément qui a ouvert. Les quatre manques de la
version bricolée, réglés par un appel de fonction.
L’élément est disponible partout depuis 2022 ; il n’y a plus de version de navigateur à attendre ni de solution de repli à écrire.
2. Le nom : ce que le lecteur d’écran annonce
À l’ouverture, un lecteur d’écran annonce le rôle — « dialogue » — et le nom de la fenêtre. Sans nom, l’utilisateur sait qu’un dialogue s’est ouvert, mais pas lequel. Le titre est déjà là : on le relie.
<dialog id="confirmation" aria-labelledby="titre-confirmation">
<h2 id="titre-confirmation">Retirer la page de l'audit ?</h2>
…
</dialog> 3. Le focus initial : sur l’action la moins risquée
Par défaut, le focus se pose sur le premier élément focalisable de la fenêtre.
Dans un dialogue de confirmation, on choisit où il se pose : sur l’action qui
n’engage à rien. autofocus est fait pour ça — dans un <dialog>, il ne
s’applique qu’à l’ouverture, pas au chargement de la page.
<form method="dialog">
<button value="annuler" autofocus>Annuler</button>
<button value="confirmer">Retirer la page</button>
</form> 4. La fermeture : un formulaire, pas un écouteur
method="dialog" ferme la fenêtre à l’activation de n’importe quel bouton du
formulaire, et dépose la value du bouton choisi dans dialogue.returnValue.
Pas d’écouteur de clic par bouton : un seul événement close, où qu’on lise la
décision.
dialogue.addEventListener('close', () => {
if (dialogue.returnValue === 'confirmer') {
// retirer la page
}
}); Le retour du focus au bouton d’ouverture, lui, est automatique — quelle que soit la façon dont la fenêtre s’est fermée.
Au clavier
| Touche | Effet |
|---|---|
| Tab | Passe à l’élément suivant dans la modale ; après le dernier, revient au premier. |
| Maj + Tab | Même circulation, en arrière. |
| Échap | Ferme la modale ; le focus revient au bouton qui l’a ouverte. |
| Entrée / Espace | Active le bouton qui a le focus ; via method="dialog", ferme la fenêtre. |
Ce que le lecteur d’écran restitue
À l’ouverture, avec le code ci-dessus, un lecteur d’écran annonce trois choses : le nom de la fenêtre, son rôle, et l’élément qui reçoit le focus — de l’ordre de « Retirer la page de l’audit ?, dialogue — Annuler, bouton ». La formulation exacte varie d’un lecteur à l’autre ; les trois informations, non. Si l’une manque à l’appel — le rôle absent, un nom vide — c’est le balisage qu’il faut regarder, pas le lecteur.
Pendant que la fenêtre est ouverte, la navigation du lecteur d’écran est elle aussi confinée à la modale : l’arrière-plan inerte n’existe plus pour personne, et c’est le comportement attendu.
Checklist
- Utilisez
<dialog>etshowModal()— pas deuxdivet du JavaScript. - Donnez un nom à la fenêtre :
aria-labelledbyvers son titre. - Posez le focus initial sur l’action la moins risquée, avec
autofocus. - Fermez par
method="dialog"; ne supprimez jamais la fermeture par Échap. - Vérifiez le retour du focus : fenêtre fermée, il est sur le bouton d’ouverture.
Les critères RGAA en jeu
- Critère 7.1 — Compatibilité des scripts
Une modale est un script : elle doit exposer son rôle de dialogue, son nom et son caractère modal aux technologies d'assistance — c'est ce que l'élément dialog et aria-labelledby déclarent.
- Critère 7.3 — Contrôle des scripts au clavier
Ouvrir, choisir, fermer : les trois se font au clavier seul. Une modale qui ne se ferme qu'à la souris échoue ici.
- Critère 12.8 — Cohérence de l’ordre de tabulation
À l'ouverture, le focus entre dans la modale ; à la fermeture, il revient sur le bouton qui l'a ouverte. Un focus abandonné en haut de page casse l'ordre de tabulation.
- Critère 12.9 — Absence de piège au clavier
Le focus est retenu dans la modale — c'est voulu — mais il doit toujours pouvoir en sortir : Échap ou un bouton de fermeture, accessibles au clavier.
- Critère 10.8 — Contenus cachés ignorés
Pendant que la modale est ouverte, le reste de la page est caché aux technologies d'assistance ; à la fermeture, il redevient accessible. Un arrière-plan seulement assombri, mais toujours parcourable, échoue ici.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Critère 7.1 — Compatibilité des scripts et 7.3 — Contrôle au clavier : les deux fiches détaillent ce qu’un audit vérifie sur tout composant scripté.
- Le glossaire du référentiel : « pris de focus », « composant d’interface » — les termes exacts que le RGAA emploie.
<dialog>sur MDN et le motif Dialog de l’ARIA APG : la référence de comportement dont ce guide est l’application.
Sources
- ARIA APG — Dialog (Modal) Pattern — le contrat de comportement
- MDN —
<dialog>— la référence de l’élément - WCAG — Understanding 2.4.3 Focus Order — pourquoi le focus doit être conduit
- DSFR — Modale — l’implémentation de l’État français