Skip to main content Accessibility Feedback

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!