Creating interactive popups can greatly enhance user engagement on websites. This implementation showcases a simple yet effective way to create custom popups using native HTML <dialog> elements, accompanied by CSS for styling and JavaScript for functionality.
HTML Structure for Popups
The HTML structure includes two main sections: one with buttons to trigger the popups and another with the popup <dialog> elements themselves, each containing a subscription form.
<main>
<!-- Trigger buttons for the popups -->
<section class="cta-wrapper">
<button class="modal-opener" data-modal="#modal-newsletter">
Open popup
</button>
<button class="modal-opener" data-modal="#modal-newsletter-2">
Open popup 2
</button>
</section>
<!-- Dialog elements (popups) -->
<dialog class="modal" id="modal-newsletter">
<button class="button-close-modal">X</button>
<h2>Subscribe to my Newsletter</h2>
<p>Get access to exclusive content that only share with my email list</p>
<label for="email">Enter your email:</label>
<input type="email" id="email" name="email" />
</dialog>
<dialog class="modal" id="modal-newsletter-2">
<button class="button-close-modal">X</button>
<h2>Another modal</h2>
<p>Get access to exclusive content that only share with my email list</p>
<label for="email-2">Enter your email:</label>
<input type="email" id="email-2" name="email" />
</dialog>
</main>
Styling with CSS
The CSS ensures that the popups are visually distinct and properly layered over other content. A no-scroll class is also defined to prevent scrolling when a popup is active.
html {
height: 100%;
}
body {
margin: 0;
min-height: 100%;
display: grid;
grid-auto-flow: row;
grid-template-rows: auto 1fr auto;
}
body.no-scroll {
margin-right: var(--scrollbarsize);
overflow: hidden;
}
.modal {
padding: 2rem;
border: 1px solid #eee;
width: max-content;
max-width: 100%;
background-color: #fff;
z-index: 10;
}
.modal::backdrop {
background-color: hsl(250, 100%, 50%, 0.25);
}
.button-close-modal {
display: block;
font-size: 2rem;
font-weight: bold;
margin-left: auto;
}
Interactive functionality with JavaScript
The JavaScript code listens for the DOMContentLoaded event to ensure the DOM is fully loaded before attaching event listeners to the buttons and dialog elements for opening and closing the popups.
window.addEventListener("DOMContentLoaded", (event) => {
// Loop through the buttons and attach a listener to open the associated modals
const openModalButtons = document.querySelectorAll(".modal-opener");
if (openModalButtons.length) {
openModalButtons.forEach((openButton) => {
const associatedId = openButton.dataset.modal;
if (associatedId) {
const dialog = document.querySelector(associatedId);
if (dialog) {
// Listener for opening the modal
openButton.addEventListener("click", (e) => {
// Set the size of the scrollbar as a CSS variable
document.documentElement.style.setProperty(
"--scrollbarsize",
`${window.innerWidth - document.documentElement.clientWidth}px`
);
// Open the associated modal
dialog.showModal();
// Prevent the user from scrolling
document.body.classList.add("no-scroll");
});
// Listener for closing the modal
dialog.addEventListener("click", (e) => {
const dialogDimensions = dialog.getBoundingClientRect();
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom ||
e.target.matches(".button-close-modal")
) {
// Close the open modal
dialog.close();
// Re-enable scrolling
document.body.classList.remove("no-scroll");
}
});
} else {
console.log(
'No associated modal found; maybe the "data-modal" attribute is empty or incorrect.'
);
}
}
});
}
});
Complete code integration
See the Pen Custom Popups with HTML, CSS, and JavaScript by LaTableRouge (@LaTableRouge) on CodePen.
Additional resources
For detailed documentation and best practices related to the <dialog> element and its usage, the following resources can be helpful:
This simple yet robust implementation allows developers to integrate custom popups into their web projects, enhancing the user interface and interaction without the need for third-party libraries.

Leave a Reply