Pour rappel <dialog> permet de créer des boîtes de dialogue (modales, popups, popins, elles ont tant de noms) en HTML sans plus avoir à tout gérer en CSS+JavaScript pour positionner un élément <div> en absolu.
Et on a aussi connu cela : une popin qui se ferme quand on appuie sur echap alors qu'on voulait forcer l'utilisateur à valider un formulaire, ou à l'inverse une modale qu'on ne peut fermer qu'avec un bouton alors qu'un clic en dehors serait tellement plus naturel. Jusqu'ici, la solution consistait à empiler du JavaScript pour gérer ça à la main.
Désormais, un simple attribut HTML suffit.
Mentionné par Una Kravets et Bramus Van Damme à la Google I/O 2026.
Comment ça marche ?
L'attribut closedby s'ajoute directement sur l'élément <dialog> et accepte trois valeurs :
any— le dialogue se ferme via la touche Échap, un geste natif (retour arrière sur mobile), ou un clic en dehors (correspond à ce qu'on appelle un light dismiss).closerequest— fermeture via la touche Echap ou geste natif uniquement, pas de clic en dehors. C'est le comportement par défaut d'une modale ouverte avecshowModal().none— fermeture uniquement via code (bouton, soumission de formulaire…), aucune alternative native.
Exemples rapides :
<!-- On peut cliquer à côté pour fermer -->
<dialog closedby="any">
<p>Aperçu rapide, fermable au moindre clic extérieur.</p>
<button onclick="this.closest('dialog').close()">Fermer</button>
</dialog>
<!-- Aucune fermeture "accidentelle" possible -->
<dialog closedby="none">
<p>Formulaire critique. On ne vous laisse pas esquiver comme ça.</p>
<button onclick="this.closest('dialog').close()">Valider et fermer</button>
</dialog>
Et sans closedby ?
Si l'attribut est absent ou invalide, le navigateur applique un comportement automatique :
- showModal() → se comporte comme closedby="closerequest" (Echap fonctionne).
- show() ou attribut open → se comporte comme closedby="none" (rien ne ferme sans code).
Autrement dit, rien ne change pour vos éléments existants. Ouf la rétrocompatibilité.
Compatibilité navigateurs
À ce jour, le support atteint environ 70 % de couverture globale d'après Caniuse ce qui est encourageant mais insuffisant pour un usage en production sans y réfléchir.
| Navigateur | Support |
|---|---|
| Chrome / Edge | ✅ depuis la version 134 |
| Firefox | ✅ depuis la version 141 |
| Opera | ✅ depuis la version 119 |
| Safari (macOS & iOS) | ❌ pas encore supporté |
🐌 Safari reste en retrait... et tant que ce n'est pas supporté un fallback JavaScript pour le light dismiss peut faire l'affaire :
// Fallback pour les navigateurs sans closedby="any"
document.querySelectorAll('dialog[closedby="any"]').forEach((dialog) => {
document.addEventListener('click', (e) => {
if (dialog.open && !e.composedPath().includes(dialog)) {
dialog.close();
}
});
});
Accessibilité
L'attribut closedby agit uniquement sur la fermeture, il ne modifie pas la sémantique de l'élément. Les bonnes pratiques habituelles restent donc :
closedby="any": le clic en dehors ferme la boîte de dialogue, vérifiez que ce comportement est prévisible pour les utilisateurs de lecteurs d'écran. Un clic accidentel à côté d'un formulaire partiellement rempli peut surprendre. Réservez cette valeur aux interactions légères et non critiques (petites popups d'information ou de prévisualiation).closedby="none": si l'utilisateur ne peut pas fermer via la touche Échap ni en cliquant en dehors, il doit impérativement y avoir un bouton de fermeture, accessible au clavier et aux technologies d'assistance.- Gestion du focus : à l'ouverture, le focus doit aller dans la modale ; à la fermeture, il doit revenir sur l'élément déclencheur (qui a ouvert la modale, par exemple un bouton).
- Libellé/titre : pensez à
aria-labelledby(pointant vers le titre) et éventuellementaria-describedbypour les descriptions. L'élément<dialog>expose déjà le bon rôle ARIA, mais sans nom accessible les lecteurs d'écran annoncent une boîte de dialogue anonyme.
Commenter
Vous devez être inscrit et identifié pour utiliser cette fonction.
Connectez-vous
Pas encore inscrit ? C'est très simple et gratuit.