Prevent keyboard traps in interactive components

Content available in English only.

Accessibility isn't just about avoiding violations — it's about ensuring that everyone can use your product with confidence. This guide explains each rule's intent, highlights common issues, and shows how to fix them according to WCAG and the European Accessibility Act (EAA).

These guidelines do not replace the official WCAG standards. They’re concise, developer-focused notes to help you identify and fix issues effectively.

Never block Tab navigation; always provide a clean way in and out.

Overview

Why this matters

A keyboard trap blocks navigation and can prevent users from reaching primary actions or exiting components.

How to fix this issue

Allow bidirectional keyboard navigation in and out of components. Only trap focus where explicitly required (such as active modal dialogs), and always provide a reliable exit path.

Automated detection · Manual review recommended

Developer Guidance

Model focus behavior as component state: inactive, active, and closing. Only constrain focus while active and restore prior focus on close. Do not globally prevent Tab; if needed (for modal dialogs), cycle between first and last tabbable nodes only. Add automated keyboard-walk tests that assert both entry and exit paths.

Code Examples

Incorrect Implementation

document.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') e.preventDefault();
});

Correct Implementation

const modal = document.querySelector('#modal');
const first = modal.querySelector('[tabindex], button, a, input, select, textarea');
const last = modal.querySelector('[data-last-focusable]');

modal.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') closeModal();
  if (e.key === 'Tab' && e.shiftKey && document.activeElement === first) {
    e.preventDefault();
    last.focus();
  }
});

Real-World Implementation

Before

<div role="dialog" open>
  <input>
  <button>Confirm</button>
</div>
<script>document.addEventListener('keydown', e => { if (e.key === 'Tab') e.preventDefault(); });</script>

After

<dialog id="confirmDialog">
  <input>
  <button>Confirm</button>
  <button>Cancel</button>
</dialog>
<script>
  // Trap only while dialog is open, restore focus on close
</script>

CSS Example (Guidance)

/* Visual outline for focusable elements inside modal */
.modal :focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

/* For hidden regions, remove focusability in HTML/JS (e.g., tabindex='-1', disabled, or inert). */

Manual Testing

  1. 1. Navigate to the component with keyboard only.
  2. 2. Confirm Tab and Shift+Tab both work through all reachable controls.
  3. 3. Verify users can exit component via standard keys or explicit close action.
  4. 4. Repeat during open, close, and error states to catch state-specific traps.
  5. 5. Run automated keyboard traversal tests in CI for regression protection.

Related Operable Rules

eu icon getwcag

Trusted by organizations across Europe working toward WCAG and EAA conformance