Utiliser l’élément HTML dialog pour construire ses modales
25 juin 2023
De nombreux articles mettent en avant la simplicité d’utilisation de l’élément HTML dialog
pour construire des modales. Il y a cependant certaines spécificités à surmonter si l’on souhaite se baser dessus pour mettre en place un système de modales complet dans nos projet.
Une modale simple
Pour une modale avec en-tête, corp et pied qui utilise l’élément dialog
voici le HTML :
<dialog id="theDialog">
<div class="dialog-header">
<h2>The modal title</h2>
<span data-closeModal="true">X</span>
</div>
<div class="dialog-body">
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere, consectetur officiis possimus earum
inventore nostrum quia modi doloribus! Impedit perferendis ab velit nisi a saepe veniam sit,
accusamus beatae. Iusto quisquam autem nostrum reprehenderit, vero incidunt iure porro, nulla id
harum, corporis eos eligendi at delectus tempore quo doloremque aliquid.
</p>
</div>
<div class="dialog-footer">
<button class="gray" data-closeModal="true" >Fermer</button>
<button >Valider</button>
</div>
</dialog>
<button class="btn" onclick="theModal.showModal()">
Open the modal
</button>
Voici le CSS :
dialog{
border: none;
border-radius: 1rem;
width: min( 100% - 3rem, 800px );
flex-direction: column;
justify-content: space-between;
padding: 0;
}
dialog[open]{
display: flex;
}
dialog>div{
padding: 1rem;
}
dialog>:is(.dialog-header, .dialog-footer){
flex: 60px;
}
dialog>.dialog-header{
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
dialog>.dialog-header span{
cursor: pointer;
font-weight: 700;
width: 50px;
text-align: center;
opacity: 0.5;
}
dialog>.dialog-footer{
border-top: 1px solid #eee;
text-align: right;
}
Et voici le Javascript :
const theModal = document.getElementById('theDialog');
theModal.querySelectorAll( 'button[data-closeModal]' ).forEach( oneButton => {
oneButton.onclick = function () {
theModal.close();
};
});
L’élément dialog
est disponible nativement en HTML5 avec :
- Des méthodes pour ouvrir/fermer la modale
- Un pseudo-élément
backdrop
qui correspond au background - Une hauteur max qui l’empêche de ‘déborder’ hors du
viewport
- Une gestion automatique du
z-index
. Si vous ouvrez une modale, elle est directement au premier plan.
Tout cela simplifie la structure HTML à mettre en place, mais également le Javascript et le CSS. Il reste cependant quelques spécificités.
Flexbox et Scroll du corp de la modale
Dans notre implémentation, l’élément dialog
est en display:flex
et flex-direction:column
, ce qui permet de conserver le header
et le footer
en haut et en bas de l’élément dialog
. Le body
pourra également prendre le reste de la hauteur disponible.
Si le contenu de l’élément dialog
est trop important et qu’il atteint sa hauteur max ( la hauteur du viewport
), il va devenir scrollable dans son ensemble. Ce n’est pas ce que l’on souhaite dans la majorité des cas. On veut que seul le body
soit scrollable si besoin :
Pour cela, on rajoute un peu de CSS :
dialog>.dialog-body{
overflow: auto;
}
Mettre en forme le fond
Le ‘fond’ de la modale est un pseudo élément backdrop
que l’on pourra styliser soi même :
dialog::backdrop {
background: rgba(80, 80, 80, 0.2);
backdrop-filter: blur(10px);
}
Fermeture de la modale en cliquant sur le fond
Il n’y a pas de mécanisme natif pour fermer la modale lorsque l’on clique sur le fond, il faut le mettre en place soi même :
theModal.addEventListener("click", function( event ){
if ( event.target === theModal )
{
theModal.close();
}
});
Animation d’ouverture et de fermeture
L’animation d’ouverture est simple à mettre en place en CSS :
dialog[open] {
animation: showDialog 0.3s ease normal;
}
@keyframes showDialog{
from {opacity: 0;transform: translateY(-20%);}
to {opacity: 1;transform: translateY(0%);}
}
Par contre, la méthode native close()
passe directement l’élément dialog
en display:none
.
Pour animer la fermeture du dialog
, il faudra donc d’abord lui appliquer une animation puis, une fois l’animation terminée, appeler la méthode close()
. On utilise pour cela un attribut closing
pour déclencher l’animation en CSS :
dialog[closing] {
animation: closeDialog 0.35s ease normal;
}
@keyframes closeDialog{
from {opacity: 1;transform: translateY(0%);}
to {opacity: 0;transform: translateY(-20%);}
}
let closeModal = ( theModal) => {
theModal.setAttribute( 'closing', true );
setTimeout(() => {
theModal.close();
theModal.removeAttribute( 'closing' );
}, 300 );
}
theModal.querySelectorAll( 'button[data-closeModal]' ).forEach( oneButton => {
oneButton.onclick = function () {
closeModal( theModal );
};
});
Et voila, on parvient à un reconstruire un système de modale complet avec l’élément dialog
.