The simplest way I found to implement modals. This snippet will allow you to add multiple modals onto a page.
<dialog class="modal" id="modal-1">
<button class="close-modal">Close</button>
<div class="modal__content">
Modal #1 content goes here.
</div>
</dialog>
<dialog class="modal" id="modal-2">
<button class="close-modal">Close</button>
<div class="modal__content">
Modal #2 content goes here.
</div>
</dialog>
<button class="open-modal" data-target="#modal-1">Open Modal 1</button>
<button class="open-modal" data-target="#modal-2">Open Modal 2</button>
The octothorpe (# symbol) in the data-target value is required for this to work.
.modal {
display: block; /** <-- Required to make the animation work */
max-width: 1400px;
width: 90%;
opacity: 0;
transform: translateY(15%);
transition: transform 0.4s ease, opacity 0.2s ease;
border: none;
visibility: hidden;
overflow: visible;
}
.modal::backdrop {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(2px);
}
.modal[open] {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.close-modal {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
const initModals = () => {
// Guard: if no modal on page
if(!document.querySelector(".modal")) return;
const modals = document.querySelectorAll('.modal');
const openButtons = document.querySelectorAll('[data-target]');
const closeButtons = document.querySelectorAll('.close-modal');
// Open modal
openButtons.forEach((button) => {
button.addEventListener('click', (e) => {
e.preventDefault();
const modal = document.querySelector(button.dataset.target);
modal.showModal();
});
});
// Close modal
closeButtons.forEach((button) => {
button.addEventListener('click', () => {
const modal = button.closest('.modal');
modal.close();
});
});
// Close on outside click
modals.forEach((modal) => {
modal.addEventListener("click", e => {
const dialogDimensions = modal.getBoundingClientRect()
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom
) {
modal.close()
}
})
});
}
Run the function after the page is done loading:
window.addEventListener("DOMContentLoaded", () => {
initModals();
});
If you have a video in your modal and need it to stop playing when the modal is closed, use this function:
const stopVideo = ( element ) => {
let iframe = element.querySelector( 'iframe');
let video = element.querySelector( 'video' );
if ( iframe ) {
let iframeSrc = iframe.src;
iframe.src = iframeSrc;
}
if ( video ) {
video.pause();
}
};
Complete JavaScript code with function to stop videos on close:
const initModals = () => {
// Guard: if no modal on page
if(!document.querySelector(".modal")) return;
const modals = document.querySelectorAll('.modal');
const openButtons = document.querySelectorAll('[data-target]');
const closeButtons = document.querySelectorAll('.close-modal');
// Open modal
openButtons.forEach((button) => {
button.addEventListener('click', (e) => {
e.preventDefault();
const modal = document.querySelector(button.dataset.target);
modal.showModal();
});
});
// Close modal
closeButtons.forEach((button) => {
button.addEventListener('click', () => {
const modal = button.closest('.modal');
modal.close();
stopVideo(modal);
});
});
// Close on outside click
modals.forEach((modal) => {
modal.addEventListener("click", e => {
const dialogDimensions = modal.getBoundingClientRect()
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom
) {
modal.close()
stopVideo(modal);
}
})
});
// Stop video when modal is closed (optional - remove if videos will ever exist in the modal)
const stopVideo = ( element ) => {
let iframe = element.querySelector( 'iframe');
let video = element.querySelector( 'video' );
if ( iframe ) {
let iframeSrc = iframe.src;
iframe.src = iframeSrc;
}
if ( video ) {
video.pause();
}
};
}