FrontendPro

93Implement an accessible focus trap for a dialog

mediumAbout 40 minutesCodingaccessibilityfocuskeyboarddom

Problem

When a modal dialog is open, keyboard focus must stay inside it. Implement createFocusTrap(container, { initialFocus, returnFocus = true, onEscape } = {}) returning { activate(), deactivate() }:

  • activate() remembers the element that had focus, then focuses initialFocus (an element), or the first tabbable element in the container, or the container itself (give it tabIndex = -1 if needed).
  • While active, Tab on the last tabbable element moves focus to the first, and Shift+Tab on the first moves to the last.
  • If focus somehow lands outside the container (a click, a script), move it back inside.
  • Escape calls onEscape.
  • deactivate() removes every listener and, if returnFocus, focuses the element that had focus before activate().

Tabbable means: a[href], button, input, select, textarea, [tabindex] and [contenteditable] elements that are not disabled, not tabindex="-1", and not hidden (inside [hidden] or with display: none).

Try it yourself

Write your solution, run it, then submit to check it against the tests.

App.jsxReact + DOM

Step-by-step

Query the candidates with one selector, then filter out disabled ones, tabindex="-1", and hidden ones (el.closest("[hidden]") or getComputedStyle(el).display === "none", and elements with no client rects). Compute the list at the moment of each Tab press, because the dialog content can change while it is open.

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 5 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever