Critical Requirements
- Focus Trap: Tab focus must cycle only within the modal while it is open.
- Inert Background: Content outside the modal must be hidden from screen readers (
aria-hidden="true") and unreachable by keyboard. - Escape Key: Pressing
Escmust close the modal. - Focus Restoration: Closing the modal must return focus to the trigger button.
The Native <dialog>
The modern and robust way to solve this.
const dialog = document.querySelector('dialog');
dialog.showModal(); // Activates focus trap and backdrop automatically
dialog.close(); // Returns focus
<dialog aria-labelledby="dialog-title">
<h2 id="dialog-title">Terms of Service</h2>
<p>...</p>
<button onclick="this.closest('dialog').close()">Close</button>
</dialog>