Revisiting how to dismiss native HTML dialog elements when the backdrop is clicked
Last month, I wrote about how to dismiss native HTML dialog elements when the backdrop is clicked using the [closedby] attribute.
My buddy Konnor Rogers shared a great little trick for handling it in browsers that don’t have support yet.
By default, browsers treat the ::backdrop on a <dialog> element as part of the <dialog> itself.
That makes detecting clicks outside of the <dialog> with JavaScript difficult…
document.addEventListener('click', (event) => {
// This logs the <dialog> element when you click the ::backdrop
console.log(event.target);
});
… or so I thought!
If you set pointer-events to none on the dialog::backdrop, the behavior changes.
.dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
pointer-events: none;
}Now, clicks on the ::backdrop register on the <html> element instead.
This means you can check if the click was inside the <dialog> element itself, and if not, close it.
document.addEventListener('click', (event) => {
// Ignore clicks inside the <dialog>
if (event.target.closest('dialog')) return;
// Otherwise, close the open <dialog>
const dialog = document.querySelector('dialog[open]');
dialog?.close();
});
Thanks Konnor!