Normes · ARIA

Rôle Fenêtre

dialog

Marque un conteneur comme une boîte de dialogue modale ou non modale. Utilisez l'élément natif <dialog> avec showModal() — il gère nativement le piège de focus, le top-layer, le backdrop et la fermeture via Échap. Recourez à role="dialog" uniquement quand l'élément natif est impossible.

Quand l’utiliser

Utilisez <dialog> ouvert via .showModal(). L’élément natif est pris en charge par tous les navigateurs actuels ; il gère l’arrière-plan inerte, le piège de focus, la fermeture par Échap, le hook de style ::backdrop et le rendu en top-layer. Il vous épargne environ 200 lignes de JavaScript fragile.

Recourez à role="dialog" sur un <div> uniquement dans les cas suivants :

  • Vous supportez des navigateurs antérieurs à Chrome 37 / Firefox 98 / Safari 15.4 (peu probable en 2026).
  • Le design impose une boîte de dialogue qui ne peut pas vivre dans le top-layer (rare).
  • Vous corrigez une modale personnalisée inaccessible lors d’un refactoring.

Toute boîte de dialogue DOIT avoir un nom accessible (aria-labelledby pointant vers un titre visible est le pattern le plus solide). Les dialogues modaux nécessitent également aria-modal="true".

Contrat clavier + focus

Selon le pattern APG dialog (modal) :

  • À l’ouverture, le focus se déplace vers le premier élément focusable à l’intérieur du dialogue (souvent le bouton de fermeture ou le champ principal).
  • Tab et Shift+Tab font circuler le focus DANS le dialogue — un « piège de focus ». Tab depuis le dernier élément revient au premier ; Shift+Tab depuis le premier revient au dernier.
  • Échap ferme le dialogue.
  • À la fermeture, le focus retourne sur l’élément qui a ouvert le dialogue. Sauvegarder et restaurer le focus est non négociable ; les utilisateurs qui perdent leur position n’ont plus de repère.
  • Le reste de la page est inert (ou aria-hidden="true" + non-focusable en solution de repli) pendant que le dialogue est ouvert.

Erreurs courantes

  • Boîte de dialogue personnalisée sans piège de focus. Tab sort du dialogue et passe derrière lui ; les utilisateurs perdent le contexte.
  • Focus non restauré sur le déclencheur à la fermeture. Le prochain Tab atterrit sur le corps du document.
  • Le contenu en arrière-plan reste accessible via Tab même s’il est visuellement masqué derrière le dialogue.
  • Absence de nom accessible. Le dialogue s’ouvre et le lecteur d’écran annonce uniquement « dialog ».
  • Boîte de dialogue personnalisée sans aria-modal="true" — les technologies d’assistance la traitent comme du contenu en ligne.
  • Échap ferme le dialogue, mais celui-ci est rendu via un portail qui perd le focus clavier pendant l’animation de fermeture.

Exemple

<!-- Préféré -->
<dialog id="confirm">
  <h2>Supprimer ce brouillon ?</h2>
  <p>Cette action est irréversible.</p>
  <form method="dialog">
    <button value="cancel">Annuler</button>
    <button value="delete" autofocus>Supprimer</button>
  </form>
</dialog>
<script>
  document.getElementById('confirm').showModal();
</script>

<!-- Quand <dialog> est impossible -->
<div role="dialog" aria-modal="true" aria-labelledby="dlgTitle">
  <h2 id="dlgTitle">Modifier le profil</h2>

</div>