revision:
Click this trigger..to open a modal.
Close a modal by: 1/ clicking off to the side, 2/ clicking the X, or 3/ pressing Escape.
You have opened the first modal!
Now, open the second modal by clicking the link.
Second modal !Nice, the second modal.
<div class="spec"> <p><a href="#" class="modal-trigger" data-modal-id="modal1"> Click this trigger</a>..to open a modal.</p> <p>Close a modal by: 1/ clicking off to the side, 2/ clicking the X, or 3/ pressing Escape.</p> <div class="modal-wrapper" id="modal1"> <section class="modal-window"> <header class="modal-header"> <h3>The first modal</h3> <button type="button" class="close-modal-button" aria-label="Close modal window">X</button> </header> <p>You have opened the first modal!</p> <p>Now, open the second modal by clicking the link.</p> <a href="#" class="modal-trigger" data-modal-id="modal2"> Second modal</a> !</p> </section> </div> <div class="modal-wrapper" id="modal2"> <section class="modal-window"> <header class="modal-header"> <h3>The second modal. 🤯</h3> <button type="button" class="close-modal-button" aria-label="Close modal window">X</button> </header> <p>Nice, the second modal.</p> </section> </div> </div> <style> .modal-wrapper {align-items: center; bottom: 0; display: flex; flex-wrap: wrap; height: 100vh;justify-content: center;left: 0; opacity: 0;position: fixed; right: 0; transition: all 0.2s ease-in-out; visibility: hidden; width: 40%; z-index: 1000;} .modal-wrapper.visible {opacity: 1;visibility: visible;} .modal-window {background-image: linear-gradient(red, yellow, black);border-radius: 1vw; box-shadow: 0 .3vw .7vw rgba(0, 0, 0, 0.3); padding: 2vw; transform: scale(0); transition: 0.2s ease-in-out all;} .modal-wrapper.visible .modal-window {transform: scale(1);} .modal-header {align-items: center;border-bottom: 0.2vw solid blue; display: flex; justify-content: space-between; margin-bottom: 2vw; padding-bottom: 2vw;} .close-modal-button {border: none; background-color: transparent; color: darkgreen; cursor: pointer; font-size: 2vw; padding: 0.2vw; } .close-modal-button:hover {color: black;} .modal-trigger {color: blue; cursor: pointer; text-decoration: underline;} </style> <script> // Stack of modals let currentlyOpenModals = []; const noModalsOpen = () => !currentlyOpenModals.length; const openModal = modalId => { const modalWrapper = document.getElementById(modalId); modalWrapper.classList.add("visible"); currentlyOpenModals.push(modalWrapper); }; // By definition, it's always the topmost modal that will be closed first const closeTopmostModal = () => { if (noModalsOpen()) { return; } const modalWrapper = currentlyOpenModals[currentlyOpenModals.length - 1]; modalWrapper.classList.remove("visible"); currentlyOpenModals.pop(); }; const modalTriggers = document.querySelectorAll(".modal-trigger"); modalTriggers.forEach(modalTrigger => { modalTrigger.addEventListener("click", clickEvent => { const trigger = clickEvent.target; const modalId = trigger.getAttribute("data-modal-id"); openModal(modalId); }); }); // Otherwise, clicking the content of a modal will propagate the click to the modal wrapper, // and that will close the entire thing. That's not what we want! document.querySelectorAll(".modal-window").forEach(modal => { modal.addEventListener("click", clickEvent => { clickEvent.stopPropagation(); }); }); const modalWrappers = document.querySelectorAll(".modal-wrapper"); modalWrappers.forEach(modalWrapper => { modalWrapper.addEventListener("click", () => { closeTopmostModal(); }); }); document.querySelectorAll(".close-modal-button").forEach(closeModalButton => { closeModalButton.addEventListener("click", () => { closeTopmostModal(); }); }); document.body.addEventListener("keyup", keyEvent => { if (keyEvent.key === "Escape") { closeTopmostModal(); } }); </script>