← スキル一覧に戻る

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📅 2026年1月23日
SKILL.md
name: focus-management description: Keyboard focus management patterns for accessibility. Covers focus traps, roving tabindex, focus restore, skip links, and FocusScope components for WCAG-compliant interactive widgets. Use when implementing focus traps or keyboard navigation. context: fork agent: accessibility-specialist version: 1.0.0 tags: [accessibility, focus, keyboard, a11y, trap] allowed-tools: [Read, Write, Edit, Grep, Glob] author: OrchestKit user-invocable: false
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
| Decision | Option A | Option B | Recommendation |
|---|---|---|---|
| Trap vs Contain | FocusTrap (strict) | FocusScope (soft) | Trap for modals, Scope for popovers |
| Restore strategy | Trigger element | Last focused | Always restore to trigger |
| Skip links | Single main skip | Multiple landmarks | Multiple for complex layouts |
| Initial focus | First focusable | Auto-focus input | Context-dependent, prefer inputs |
| Focus visible | Browser default | Custom outline | Custom :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; }
Related Skills
a11y-testing- Test focus management with Playwright and axedesign-system-starter- Focus indicators in design tokensmotion-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
スコア
総合スコア
75/100
リポジトリの品質指標に基づく評価
✓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
レビュー
💬
レビュー機能は近日公開予定です
