Skip to main content Accessibility Feedback

How to dismiss native HTML dialog elements when the backdrop is clicked

The HTML <dialog> element is a browser-native way to create dialog modals. It handles a lot of (but not all of) the accessibility stuff out-of-the-box.

By default, the <dialog> element is closed when…

  • You explicitly run the .close() method on it, or
  • The user presses a <button> with the [formmethod="dialog"] attribute (or inside a method="dialog" form), or
  • The user presses the Esc key.

For most custom modals, clicking or tapping the backdrop, the dark area outside of the modal, also closes it. This is often referred to as light dimissal.

But browser-native <dialog> elements don’t do that.

Historically, this required some extra JavaScript to handle.

When opening a <dialog> element, you’d need to listen for clicks on the document, calculate if the click was inside or outside of the <dialog> element, and run the .close() method on it if it was.

But because of how the <dialog> element works, clicking on the backdrop often returns true when checking if the click was inside the the modal by running .closest('dialog') on the event.target.

document.addEventListener('click', (event) => {
	// This always returns true, even when clicking the :backdrop
	const isInDialog = event.target.closest('dialog');
});

You’d end up having to use to use the Element.getBoundingClientRect() method and do math. Ugh.

Now, you can do it with just HTML!

The [closedby] attribute tells browsers what methods of closing a <dialog> should be used/supported for that particular element.

  • auto works the same as not using a [closedby] at all.
  • any uses all of the normal ways to close a <dialog>, plus light dismiss or clicking the :backdrop.
  • none disables light dimiss and the Esc key. The only way to close the <dialog> is by running the .close() method or clicking a [formmethod="dialog"] button.
<dialog closedby="any">
	This dialog can be closed by clicking the backdrop outside it.
</dialog>

This is the method Kelp uses and recommends for light dismiss modals.

It currently works everywhere but Safari. I think treating it as a progressive enhancement for just one unsupporting browser is fine. There’s a polyfill or two out there, but they’re quite large for what I think is nice-to-have functionality in most cases.