Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Modal dialog has no focus trap

Open
#95 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
javascript

Research direction

Start in assets/js/modal.js, especially the custom Escape handler at lines 60–64 and the open and close paths. Check how the 400ms animation delay interacts with dialog.close() and focus. Done means keyboard focus remains managed during closing and returns to the element that triggered the modal after it closes.

Written by the indexing model from the issue text.

Description

accessibility

Summary

The site uses a native HTML <dialog> 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 <dialog> 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 <body>).

Fix

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

// 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)

Dominant language
HTML
Stars
1
Forks
6
Avg merge
1d 4h
Merged PRs (30d)
6

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from CivicTechTO/civictech.ca

All issues in CivicTechTO/civictech.ca

Similar issues

More Accessibility issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.