Frontend Patterns

Pattern

Focus Trap

Constrain keyboard focus within modal dialogs and overlays to prevent focus from escaping to background content.

Focus Trap

Problem

Keyboard users can tab out of modal dialogs and interact with content behind the overlay that’s visually hidden. Focus escapes the modal, reaching buttons and links that shouldn’t be accessible. Users must tab through all background content to cycle back to the modal, breaking the modal’s purpose of focused interaction.

Solution

Contain keyboard navigation within modals or dialogs by cycling focus between interactive elements and preventing tab from escaping. This keeps keyboard users engaged with the active context and matches how these overlays trap mouse interaction.

Example

This example demonstrates trapping keyboard focus within a modal by cycling between the first and last focusable elements.

function Modal({ children, onClose }) {
  // Track references to first and last focusable elements
  const firstElement = useRef();
  const lastElement = useRef();

  const trapFocus = (e) => {
    if (e.key === 'Tab') {
      // Shift+Tab at first element: cycle to last
      if (e.shiftKey && document.activeElement === firstElement.current) {
        lastElement.current.focus();
        e.preventDefault();
      // Tab at last element: cycle to first
      } else if (!e.shiftKey && document.activeElement === lastElement.current) {
        firstElement.current.focus();
        e.preventDefault();
      }
    }
  };

  return <div onKeyDown={trapFocus}>{children}</div>;
}

Benefits

  • Improves accessibility by preventing keyboard users from accessing hidden content behind modals.
  • Creates consistent interaction model where focus behavior matches visual presentation.
  • Meets WCAG requirements for modal dialogs and overlay components.
  • Reduces user confusion by keeping focus within the active context.

Tradeoffs

  • Requires tracking first and last focusable elements, adding implementation complexity.
  • Can trap users if the modal lacks a clear escape method like Escape key or close button.
  • May conflict with browser extensions or assistive technology that manage focus.
  • Needs careful testing across different browsers and assistive technologies.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.