CivicTechTO / CivicTechTO/civictech.ca

Modal dialog has no focus trap

Open
#95 0 comments 0 reactions 0 assignees View on GitHub
accessibility
Dominant language
HTML
Stars
1
Forks
6
Avg merge
9h 45m
Merged PRs (30d)
6

Description

## Summary

The site uses a native HTML `` element with `showModal()`, which provides some built-in accessibility behaviour. However, the current implementation in `modal.js` overrides the native Escape key handler without ensuring focus is properly managed, and focus can potentially escape the modal to the background content depending on browser/AT combinations.

## Affected location

`assets/js/modal.js`

## Details

Native `` with `showModal()` does implement a focus trap in modern browsers. However:

1. The custom Escape key handler in `modal.js:60–64` calls `closeModal()` which uses a CSS animation delay of 400ms before calling `dialog.close()`. During this window, the dialog is visually closing but still open in the DOM, which can cause focus confusion.
2. Focus is not explicitly returned to the trigger element that opened the modal after it closes — it falls back to the browser default (usually ``).

## Fix

After calling `modal.close()`, return focus to the element that triggered the modal:

```js
// Track the trigger element when opening
const openModal = (modal) => {
modal._trigger = document.activeElement; // store trigger
// ... existing open logic
modal.showModal();
};

const closeModal = (modal) => {
const trigger = modal._trigger;
// ... existing close logic (with animation timeout)
setTimeout(() => {
// ... existing cleanup
modal.close();
if (trigger) trigger.focus(); // return focus to trigger
}, animationDuration);
};
```

## WCAG criterion

2.1.2 No Keyboard Trap (Level A), 2.4.3 Focus Order (Level A)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.