Composant · Dialogues et messages

Alertdialog accessible : confirmation destructive et RGAA

Le contrat du dialogue d'alerte (role alertdialog) conforme RGAA : aria-describedby obligatoire vers le message, focus initial sur l'action sûre, Échap et retour du focus.

Un dialogue d'alerte est une fenêtre modale qui interrompt l'utilisateur pour lui communiquer un message important et obtenir une réponse : confirmation d'une action destructive, acquittement d'une erreur. Techniquement, c'est une fenêtre modale avec exactement deux différences, et tout le reste du contrat de la modale s'applique sans changement (<dialog> ouvert par .showModal(), jamais l'attribut open, boucle Tab, retour du focus sur le déclencheur) :

dialogalertdialog
Rôledialog (implicite sur <dialog>)alertdialog (à poser explicitement)
aria-describedbyOptionnelObligatoire

Pourquoi ces deux différences comptent : role="alertdialog" signale au lecteur d'écran une interruption urgente. À l'ouverture, il annonce immédiatement la description, sans attendre que l'utilisateur explore. C'est ce qui rend aria-describedby obligatoire : sans lui, l'utilisateur entend le titre et n'apprend rien de ce qu'on lui demande de confirmer.

Quand ce motif est le mauvais choix

Un dialogue d'alerte prend le focus et bloque la page : il ne se justifie que si l'utilisateur a une décision à prendre.

  • Message sans décision (« Vos modifications ont été enregistrées ») : message de statut (critère 7.5, role="status" ou role="alert"), annoncé sans déplacer le focus ni interrompre la tâche. C'est l'erreur de choix la plus courante : voler le focus pour une information sur laquelle l'utilisateur ne peut pas agir.
  • Formulaire dans une fenêtre superposée : fenêtre modale classique, sans la sémantique d'urgence.
  • Précision RGAA : un dialogue d'alerte n'est pas un « message de statut » au sens du critère 7.5, puisque le focus est déplacé ; ce critère concerne l'alternative en zone de notification, pas ce composant.

Critères RGAA applicables

Interaction clavier attendue

ToucheAction
TabÉlément focalisable suivant dans le dialogue ; boucle du dernier au premier.
Maj + TabÉlément focalisable précédent ; boucle du premier au dernier.
ÉchapFerme le dialogue sans exécuter l'action ; le focus revient sur le déclencheur.

Rôles et attributs ARIA

role="alertdialog" doit être posé explicitement : <dialog> porte implicitement role="dialog", et .showModal() ne le transforme pas. aria-describedby pointe LA phrase qui porte la décision, pas tout le corps de la boîte, en plus d'aria-labelledby vers le titre. Le focus initial (autofocus) va sur l'action la moins destructive.

<button type="button" id="supprimer-compte">Supprimer le compte</button>

<!-- role="alertdialog" explicite : showModal() ne change pas le rôle. -->
<dialog id="confirmation-suppression"
        role="alertdialog"
        aria-labelledby="titre-suppression"
        aria-describedby="message-suppression">
  <h2 id="titre-suppression">Supprimer votre compte ?</h2>

  <!-- OBLIGATOIRE. Annoncé immédiatement à l'ouverture : c'est la phrase
       sur laquelle repose la décision. -->
  <p id="message-suppression">
    Cette action supprime définitivement votre compte et vos 47 projets.
    Elle est irréversible.
  </p>

  <form method="dialog">
    <!-- autofocus sur l'action SÛRE : un appui Entrée encore en cours au
         moment de l'ouverture ne doit pas supprimer le compte. -->
    <button type="submit" value="annuler" autofocus>Annuler</button>
    <button type="submit" value="supprimer">Supprimer le compte</button>
  </form>
</dialog>
const confirmation = document.getElementById('confirmation-suppression');

document.getElementById('supprimer-compte').addEventListener('click', () => {
  confirmation.showModal(); // jamais confirmation.open = true
});

confirmation.addEventListener('close', () => {
  if (confirmation.returnValue === 'supprimer') supprimerLeCompte();
  // Le focus revient automatiquement sur le déclencheur :
  // showModal() s'en charge.
});

La description est la seule information annoncée d'office : elle doit dire ce qui va réellement se passer (« supprime définitivement vos 47 projets »), pas poser une question générique.

À ne pas faire :

<!-- role="dialog" conservé pour une confirmation destructive : la
     description n'est pas annoncée à l'ouverture. L'utilisateur entend
     « Supprimer votre compte ?, dialogue » et doit partir explorer pour
     comprendre l'enjeu. -->
<dialog role="dialog" aria-labelledby="titre-suppression">…</dialog>

<!-- alertdialog sans aria-describedby : le rôle promet un message urgent
     et il n'y a rien à annoncer. Seul le titre est restitué. -->
<dialog role="alertdialog" aria-labelledby="titre-suppression">
  <h2 id="titre-suppression">Supprimer votre compte ?</h2>
  <p>Cette action supprime vos 47 projets.</p>  <!-- jamais annoncé -->
</dialog>

<!-- aria-describedby vers tout le corps de la boîte : le titre, les boutons
     et chaque mot du balisage sont annoncés d'un bloc à l'ouverture.
     Pointer uniquement la phrase porteuse de la décision. -->
<dialog role="alertdialog" aria-describedby="corps-boite">
  <div id="corps-boite">…</div>
</dialog>

<!-- Autofocus sur le bouton destructif : un utilisateur qui maintient
     Entrée, ou l'appuie au moment où le dialogue apparaît, supprime le
     compte sans l'avoir lu. -->
<button type="submit" value="supprimer" autofocus>Supprimer le compte</button>

Défauts fréquents et impact utilisateur

  • role="dialog" conservé pour une confirmation destructive : la description n'est pas annoncée à l'ouverture ; l'utilisateur de lecteur d'écran doit explorer la boîte pour comprendre ce qu'on lui demande.
  • role="alertdialog" sans aria-describedby : le contenu de la décision est perdu ; seul le titre est restitué.
  • Autofocus sur le bouton destructif : l'action irréversible peut être déclenchée par un appui Entrée résiduel, avant toute lecture.
  • Dialogue d'alerte pour un message sans décision : le focus est volé et la page bloquée pour une information sur laquelle l'utilisateur ne peut pas agir ; un message de statut suffit.
  • aria-describedby pointant tout le corps de la boîte : l'annonce d'ouverture devient un bloc indigeste de titre, boutons et balisage.
  • Description générique (« Êtes-vous sûr ? ») : la description est la seule information annoncée d'office ; la gaspiller sur une formule vide prive l'utilisateur de l'enjeu réel.

Ce que les outils automatiques ne détectent pas

Les outils automatiques repèrent un role="alertdialog" sans nom accessible. En revanche, restent des vérifications manuelles :

  • l'absence d'aria-describedby, ou une description pointant le mauvais élément : seul un test au lecteur d'écran confirme que le message est annoncé immédiatement à l'ouverture ;
  • le focus initial placé sur l'action destructive : ouvrir le dialogue et appuyer Entrée aussitôt, rien de destructif ne doit se produire ;
  • le choix du motif lui-même : décider si le contenu justifie un dialogue d'alerte ou un simple message de statut relève du jugement humain, pas d'un scanner.

Vérifier ce composant

Protocole manuel rapide, dans cet ordre :

  1. Au lecteur d'écran : ouvrir le dialogue ; la description doit être annoncée immédiatement, sans que vous naviguiez vers elle. Si vous n'entendez que le titre, aria-describedby est absent ou pointe le mauvais élément.
  2. Test Entrée immédiat : ouvrir le dialogue et appuyer Entrée dans la foulée ; rien de destructif ne doit se produire. Si le compte est supprimé, le focus initial est sur le mauvais bouton.
  3. Au clavier seul : Échap ferme sans exécuter l'action, et le focus revient sur le déclencheur ; la boucle Tab reste confinée au dialogue.
  4. Question de fond : l'utilisateur a-t-il réellement une décision à prendre ? Sinon, ce ne devrait pas être un dialogue d'alerte.

Pour outiller ces vérifications : le simulateur de lecteur d'écran donne un premier aperçu de la restitution, et le testeur de focus visible vérifie vos styles de focus contre le fond assombri. Le guide Tester avec un lecteur d'écran explique le test réel avec NVDA ou VoiceOver.

Approfondir avec les fiches critères

Vérifier ce composant sur votre site ?

Le scan repère les défauts détectables automatiquement (rôles incohérents, champs sans étiquette, attributs ARIA orphelins) ; le reste se vérifie à la main avec les protocoles de cette fiche.

Lancer un scan gratuit

Toutes les fiches composants accessibles