Une fenêtre modale en JavaScript natif

Aujourd’hui, nouveau retour sur un de mes anciens tutoriels qui a rencontré un certain succès, mon tutoriel sur comment faire une fenêtre modale avec jQuery.

Depuis maintenant à peu près un an, tous les navigateurs majeurs supportent la balise <dialog> qui permet de créer des fenêtres modales (ça ça tombe bien).

Un des avantages de cette solution plus moderne est qu’il n’y a plus besoin d’insérer manuellement un élément de masquage de la page, maintenant il y a le pseudo-élément ::backdrop pour ça.

Comment ça marche ?

Pour le corps de la modale, rien de bien différent entre l’ancienne méthode et la nouvelle, on remplace la <div> par un <dialog>.

<dialog id="myModal">
    <div>Bonjour, je suis une fenêtre modale.
    <br/>Cliquez sur le masque pour me refermer.</div>
</dialog>

Et pour la faire s’afficher, il suffit de la sélectionner avec la méthode de votre choix (de mon côté j’ai une préférence pour querySelector), et ensuite d’appeler sa méthode showModal() dans une fonction liée au clic sur un autre élément dans la page.

const myModal = document.getElementById('myModal');
const openModal = document.getElementById('openModal');
                
openModal.addEventListener('click', () => { myModal.showModal(); });

La principale différence est dans la manière dont on gère la fermeture de la modale au clic sur le masque. En effet, avec cette technique moderne, le masque est un pseudo-élément (::backdrop), ce qui fait qu’on ne peut pas lui attacher d’eventListener.

Pour gérer cela avec cette nouvelle méthode, il faut attacher un eventListener sur la modale elle-même et voir si le clic tombe en dehors de ses limites réelles (ces limites peuvent être retrouvées avec la méthode getBoundingRectangle() de la balise <dialog>.

myModal.addEventListener('click', (e) => {
    const modalRect = myModal.getBoundingClientRect();

    if(e.clientX < modalRect.left || e.clientX > modalRect.right
    || e.clientY < modalRect.top || e.clientY > modalRect.bottom) {
        myModal.close();
    }
});

En ce qui concerne le changement de couleur du masque, une animation CSS peut être utilisée. À l’heure actuelle (début 2023), cette technique ne fonctionne que pour les navigateurs de la famille Chromium (Brave, Microsoft Edge, Google Chrome…).

#myModal::backdrop {
    background-color: rgba(0, 0, 0, .8);
    animation: fadeIn 3s ease forwards;
}
@keyframes fadeIn {
    from {
        background-color: transparent;
    }
    to {
        background-color: rgba(0, 0, 0, .8);
    }
}

Le code complet est disponible avec mes autres démonstrations.


Et voilà. J’espère vous avoir permis de vous coucher un peu moins bête ce soir, et vous dis à bientôt.

Laisser un commentaire