Back to list
yonatangross

focus-management

by yonatangross

The Complete AI Development Toolkit for Claude Code — 159 skills, 34 agents, 20 commands, 144 hooks. Production-ready patterns for FastAPI, React 19, LangGraph, security, and testing.

29🍴 4📅 Jan 23, 2026

SKILL.md


Focus Management

Essential patterns for managing keyboard focus in accessible web applications, ensuring keyboard-only users can navigate complex interactive components.

Overview

  • Building modals, dialogs, or drawers that require focus trapping
  • Implementing tab panels, menus, or toolbars with roving tabindex
  • Restoring focus after closing overlays or completing actions
  • Creating skip links for keyboard navigation
  • Ensuring focus visibility meets WCAG 2.4.7 requirements

Quick Reference

FocusScope Trap (React Aria)

import { FocusTrap } from '@react-aria/focus';

function Modal({ isOpen, onClose, children }) {
  if (!isOpen) return null;
  return (
    <div role="dialog" aria-modal="true">
      <FocusTrap>
        <div className="modal-content">
          {children}
          <button onClick={onClose}>Close</button>
        </div>
      </FocusTrap>
    </div>
  );
}

Roving Tabindex

function TabList({ tabs, onSelect }) {
  const [activeIndex, setActiveIndex] = useState(0);
  const tabRefs = useRef<HTMLButtonElement[]>([]);

  const handleKeyDown = (e: KeyboardEvent, index: number) => {
    const keyMap: Record<string, number> = {
      ArrowRight: (index + 1) % tabs.length,
      ArrowLeft: (index - 1 + tabs.length) % tabs.length,
      Home: 0, End: tabs.length - 1,
    };
    if (e.key in keyMap) {
      e.preventDefault();
      setActiveIndex(keyMap[e.key]);
      tabRefs.current[keyMap[e.key]]?.focus();
    }
  };

  return (
    <div role="tablist">
      {tabs.map((tab, i) => (
        <button key={tab.id} ref={(el) => (tabRefs.current[i] = el!)}
          role="tab" tabIndex={i === activeIndex ? 0 : -1}
          aria-selected={i === activeIndex}
          onKeyDown={(e) => handleKeyDown(e, i)}
          onClick={() => { setActiveIndex(i); onSelect(tab); }}>
          {tab.label}
        </button>
      ))}
    </div>
  );
}

Focus Restore

function useRestoreFocus(isOpen: boolean) {
  const triggerRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (isOpen) {
      triggerRef.current = document.activeElement as HTMLElement;
    } else if (triggerRef.current) {
      triggerRef.current.focus();
      triggerRef.current = null;
    }
  }, [isOpen]);
}

Key Decisions

DecisionOption AOption BRecommendation
Trap vs ContainFocusTrap (strict)FocusScope (soft)Trap for modals, Scope for popovers
Restore strategyTrigger elementLast focusedAlways restore to trigger
Skip linksSingle main skipMultiple landmarksMultiple for complex layouts
Initial focusFirst focusableAuto-focus inputContext-dependent, prefer inputs
Focus visibleBrowser defaultCustom outlineCustom :focus-visible for consistency

Anti-Patterns (FORBIDDEN)

// NEVER use positive tabindex - breaks natural tab order
<button tabIndex={5}>Bad</button>

// NEVER remove focus outline without replacement (WCAG 2.4.7)
button:focus { outline: none; }

// NEVER trap focus without Escape key handler
<FocusTrap><div>No way out!</div></FocusTrap>

// NEVER auto-focus without user expectation
useEffect(() => inputRef.current?.focus(), []);

// NEVER hide skip links permanently - must be visible on focus
.skip-link { display: none; }
  • a11y-testing - Test focus management with Playwright and axe
  • design-system-starter - Focus indicators in design tokens
  • motion-animation-patterns - Animate focus transitions accessibly

Capability Details

focus-trap

Keywords: focus trap, modal focus, dialog focus, FocusTrap, aria-modal Solves:

  • Trap focus within modals and dialogs
  • Prevent focus escaping to background content
  • Handle Escape key to close and release trap

roving-tabindex

Keywords: roving tabindex, arrow navigation, tablist, menu keyboard Solves:

  • Navigate widget items with arrow keys
  • Maintain single tab stop for composite widgets
  • Support Home/End for quick navigation

focus-restore

Keywords: focus restore, return focus, trigger focus, focus memory Solves:

  • Return focus to trigger after closing overlay
  • Preserve focus context across interactions
  • Handle focus when elements are removed from DOM

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon