Skip to content
GeeksSmith
advanced 9 min read

Building Accessible UI Primitives (Focus Trapping, Combobox, ARIA Live)

Accessible UI primitives strictly adhere to WAI-ARIA Authoring Practices: managing keyboard focus trapping (Tab/Shift+Tab), restoring trigger focus on close (Escape), associating labels via aria-labelledby/describedby, and announcing dynamic updates via aria-live.

Why it matters in interviews

Interviews at accessibility-conscious organizations (like ConveGenius, government edtech, and enterprise retail) regularly require coding accessible modals and comboboxes from scratch. Omitting focus traps or keyboard navigation causes immediate candidate rejection.

Visual & Interactive Explanation

Interactive Flow Execution

Code Examples & Implementation

Production Accessible Focus Trap Hook (useFocusTrap)
import { useEffect, useRef } from 'react';

export function useFocusTrap(isOpen: boolean, onClose: () => void) {
  const containerRef = useRef<HTMLDivElement>(null);
  const previousActiveElement = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (!isOpen) return;

    // 1. Remember element that triggered modal
    previousActiveElement.current = document.activeElement as HTMLElement;

    const container = containerRef.current;
    if (!container) return;

    // Selector for all keyboard-focusable elements
    const focusableElements = container.querySelectorAll<HTMLElement>(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    const firstElement = focusableElements[0];
    const lastElement = focusableElements[focusableElements.length - 1];

    // Focus first interactive element
    firstElement?.focus();

    const handleKeyDown = (e: KeyboardEvent) => {
      // Handle Escape key
      if (e.key === 'Escape') {
        e.preventDefault();
        onClose();
        return;
      }

      if (e.key !== 'Tab') return;

      // Handle Tab & Shift+Tab wrapping
      if (e.shiftKey) {
        if (document.activeElement === firstElement) {
          e.preventDefault();
          lastElement?.focus();
        }
      } else {
        if (document.activeElement === lastElement) {
          e.preventDefault();
          firstElement?.focus();
        }
      }
    };

    window.addEventListener('keydown', handleKeyDown);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
      // Restore focus to trigger button
      previousActiveElement.current?.focus();
    };
  }, [isOpen, onClose]);

  return containerRef;
}

Interview-Ready Answers

A fully accessible modal requires role='dialog', aria-modal='true', aria-labelledby/describedby, a keyboard focus trap cycling between interactive children, Escape key dismissal, and restoring focus to the trigger button upon closing.

Official Documentation & Specifications

Follow-up Questions & Deep Dives

Common Mistakes & Anti-Patterns

  • Building a custom modal that allows users to Tab into invisible elements behind the modal backdrop.
  • Forgetting to restore focus to the trigger button when closing a modal, causing screen readers to lose context and reset to the top of the body.
  • Using non-semantic <div onClick> without role='button', tabIndex={0}, and onKeyDown handler for Enter/Space.

Real-World Architectural Scenario

A government education portal fails a strict WCAG 2.1 AA audit because screen reader users get disoriented after submitting a search form with asynchronous results. How do you fix it?

Rate Your Readiness

Rate how comfortably you can explain this in an interview to update your global readiness gauge:

Rate your confidence: