SnippetJavaScript
Modal
Accessible modal via native <dialog>: focus restore, Escape, backdrop dismiss.
Explanation
Prefer the native `<dialog>` when you can — it provides top-layer stacking and a cancel event. This helper covers open/close, Escape, backdrop click, and restoring focus. For full Tab-cycle focus trapping, layer a small trap helper or use a battle-tested dialog library.
javascript
export function createModal(dialog) {
if (!(dialog instanceof HTMLDialogElement)) {
throw new Error('Expected <dialog> element');
}
let lastFocus = null;
function open() {
lastFocus = document.activeElement;
dialog.showModal();
const focusable = dialog.querySelector(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
focusable?.focus();
}
function close() {
dialog.close();
lastFocus?.focus?.();
}
dialog.addEventListener('click', (e) => {
const rect = dialog.getBoundingClientRect();
const inDialog =
rect.top <= e.clientY && e.clientY <= rect.bottom &&
rect.left <= e.clientX && e.clientX <= rect.right;
if (!inDialog) close();
});
dialog.addEventListener('cancel', (e) => {
e.preventDefault();
close();
});
return { open, close };
}Usage example
html
<dialog id="confirm">
<form method="dialog">
<p>Delete item?</p>
<button value="cancel">Cancel</button>
<button value="ok">Delete</button>
</form>
</dialog>
const modal = createModal(document.getElementById('confirm'));
openBtn.addEventListener('click', () => modal.open());Interview tips
- ✓Mention Escape, focus restore, and why native <dialog> helps (top layer, cancel event).
- ✓Call out full focus trap (Tab cycling) as a follow-up if not implemented.