Day 04: Modal Dialog
Open and close a modal dialog using buttons and overlay click.
JavaScript focus
- selecting the dialog and trigger buttons
- opening the dialog with the native method
- closing the dialog with the native method
- handling click events for open and close controls
- handling close behavior cleanly
- optional body class toggle for page-level styling
Nice extras
- return focus to the trigger that opened it
- support multiple trigger buttons for the same dialog
- close on backdrop click
- add a simple open / close animation class
- prevent page scroll while open with a body class
- include a confirm button and read the dialog's returnValue
MDN prep
Modal Trigger
The HTML
<section class="section modal_dialog">
<h2 class="secondary_heading">Modal Trigger</h2>
<button type="button" class="button" data-open-modal="demo-modal">Open Modal</button>
<dialog class="modal">
<div class="modal_inner">
<header class="modal_header">
<h2 class="modal_title">Modal Title</h2>
</header>
<div class="modal_body">
<p>This is placeholder content for your modal.</p>
<p>You can drop forms, text, or anything else here.</p>
</div>
<footer class="modal_footer">
<button type="button" class="button confirm_button" value="Confirm">Confirm</button>
</footer>
</div>
</dialog>
</section>
The JavaScript
function initModalDialog() {
const body = document.body;
const root = document.querySelector(".modal_dialog");
if (!root) return;
const modal = root.querySelector(".modal");
const openModal = root.querySelector(".button[data-open-modal='demo-modal']");
const confirmModal = root.querySelector(".confirm_button");
// open the modal
if (openModal) {
openModal.addEventListener("click", () => {
modal.showModal();
body.classList.add("modal_open");
});
}
// confirm and close the modal
if (confirmModal) {
confirmModal.addEventListener("click", (e) => {
const confirm = e.target;
modal.close(confirm.value);
body.classList.remove("modal_open");
});
}
function updateReturnValue() {
// do with this whatever you want
console.log(`Return value: "${modal.returnValue}"`);
}
modal.addEventListener("close", updateReturnValue);
// click the backdrop to close the modal
modal.addEventListener("click", (e) => {
if (e.target === modal) {
body.classList.remove("modal_open");
modal.close();
}
});
// hit escape to close the modal
document.addEventListener("keydown", (e) => {
if (!body.classList.contains("modal_open")) return;
if (e.key === "Escape") {
body.classList.remove("modal_open");
modal.close();
}
});
}
initModalDialog();