Skip to content

Modal dialog has no focus trap #95

@alexwolson

Description

@alexwolson

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    accessibilityAccessibility and WCAG compliance

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions