modal-dismissed-on-esc
Web validation
Pressing the Escape key is the common, expected way to close a modal dialog. When a modal ignores it, keyboard and assistive technology users must look for the close button instead. For screen reader users, screen magnifier users, and people with motor impairments, finding and reaching that button can take significant extra effort before they can get back to the main page content. Allow users to close the modal by pressing Escape. When the modal closes, move focus back to the element that opened it.
A native <dialog> element opened with showModal() closes on Escape by default. A custom modal built with role="dialog" needs a script that listens for the Escape key.
Note: A native <dialog> loses this behavior if a script calls preventDefault() on its cancel event. Only cancel the event when you have a good reason, such as asking users to confirm before discarding unsaved changes.
Pass Patterns
Native <dialog> opened with showModal()
The browser closes the modal when the user presses Escape, with no extra script.
<button id="open-settings">Settings</button>
<dialog id="settings-dialog" aria-labelledby="settings-title">
<h2 id="settings-title">Settings</h2>
<button id="close-settings">Close</button>
</dialog>
<script>
const dialog = document.getElementById("settings-dialog");
document.getElementById("open-settings").addEventListener("click", () => dialog.showModal());
document.getElementById("close-settings").addEventListener("click", () => dialog.close());
</script>Custom modal with an Escape key handler
The script closes the modal on Escape and returns focus to the button that opened it.
<button id="open-settings">Settings</button>
<div id="settings-modal" role="dialog" aria-modal="true" aria-labelledby="settings-title" hidden>
<h2 id="settings-title">Settings</h2>
<button id="close-settings">Close</button>
</div>
<script>
const modal = document.getElementById("settings-modal");
const opener = document.getElementById("open-settings");
modal.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
modal.hidden = true;
opener.focus();
}
});
</script>Fail Patterns
Custom modal with no Escape key handler
The modal can be closed only with its close button. Pressing Escape does nothing.
<div id="settings-modal" role="dialog" aria-modal="true" aria-labelledby="settings-title">
<h2 id="settings-title">Settings</h2>
<button id="close-settings">Close</button>
</div>Try It Yourself
Using a keyboard
- Use the Tab key to move to the control that opens the modal, and press Enter or Space to open it.
- Press the Escape key.
- Check whether the modal closes, and where the focus is.
Expected results: The modal closes, and focus returns to the control that opened it.
Actual results: The modal stays open, and the only way to close it is to find and activate its close button.
FAQ
Why is this validation considered a best practice?
WCAG does not require the Escape key specifically. It requires that keyboard users can leave the modal, which a keyboard accessible close button can satisfy. However, closing a modal with Escape is the expected behavior described in the ARIA Authoring Practices Guide, and many users rely on it as the quickest way out.
Why is this issue marked as Moderate?
Users can usually still close the modal with its close button, so they are not blocked. However, keyboard, screen reader, and screen magnifier users expect Escape to work, and without it they must spend extra effort finding the button before they can return to the page, so it is rated moderate.
What if Escape is the only way to close the modal?
Then the modal also has a more serious problem. If keyboard users cannot reach a close button, they may be unable to leave the modal at all, which can fail WCAG 2.1.2 No Keyboard Trap. Review the related focus-trap and no-visible-close-modal-button validations.