Modal dialogs are one of the trickiest components to make accessible. When done wrong, keyboard users can't close them, screen reader users don't know they're open, and everyone gets frustrated.
What Makes a Modal Accessible?
An accessible modal must:
- Announce itself to screen readers when it opens
- Trap focus inside while open
- Return focus to the trigger element when closed
- Be closeable with the Escape key
- Hide background content from assistive technology
The HTML Structure
<button id="open-modal-btn">Open Settings</button>
<div
id="modal"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
hidden
>
<h2 id="modal-title">Settings</h2>
<!-- Modal content -->
<button id="close-modal-btn">Save & Close</button>
</div>
Key ARIA Attributes
role="dialog": Tells screen readers this is a dialogaria-modal="true": Indicates background content is inertaria-labelledby: Points to the modal's title
The Native Dialog Element
Modern browsers support the <dialog> element, which handles much of this automatically:
<button id="open-btn">Open Settings</button>
<dialog id="settings-dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Settings</h2>
<form method="dialog">
<label for="theme">Theme</label>
<select id="theme">
<option>Light</option>
<option>Dark</option>
</select>
<button value="save">Save</button>
</form>
</dialog>
<script>
const dialog = document.getElementById('settings-dialog');
document.getElementById('open-btn').addEventListener('click', () => {
dialog.showModal();
});
</script>
The native dialog automatically:
- Traps focus
- Closes on Escape
- Makes background inert
- Returns focus when closed
Common Modal Mistakes
Not Trapping Focus
If users can Tab out of the modal to content behind it, that's a major problem.
Not Returning Focus
When the modal closes, focus should return to the element that opened it.
No Escape Key Support
Users expect Escape to close modals. Always implement this.
Testing Modals
- Can you open the modal with keyboard?
- Does focus move into the modal?
- Is focus trapped inside?
- Does Escape close it?
- Does focus return to the trigger?
- Is the modal announced by screen readers?