typescriptadvanced
useFocusTrap Hook
Traps keyboard focus within a container for accessible modals and dialogs.
typescriptPress ⌘/Ctrl + Shift + C to copy
import { useEffect, useRef, RefObject } from 'react';
const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
export function useFocusTrap<T extends HTMLElement>(active = true): RefObject<T | null> {
const ref = useRef<T | null>(null);
useEffect(() => {
if (!active || !ref.current) return;
const container = ref.current;
const focusableElements = container.querySelectorAll<HTMLElement>(FOCUSABLE);
const first = focusableElements[0];
const last = focusableElements[focusableElements.length - 1];
first?.focus();
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return;
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last?.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first?.focus();
}
}
};
container.addEventListener('keydown', handleKeyDown);
return () => container.removeEventListener('keydown', handleKeyDown);
}, [active]);
return ref;
}Use Cases
- Accessible modals
- Dialog components
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptbeginner
useLockBodyScroll Hook
Locks body scroll when active, commonly used with modals and overlays to prevent background scrolling.
Best for: Modal dialogs
#hooks#scroll
typescriptintermediate
useSpeechSynthesis Hook
Text-to-speech hook using the Web Speech API with voice selection, rate, and pitch control.
Best for: Accessibility features
#hooks#speech
typescriptintermediate
useFetch — Generic Data Fetching Hook
Custom React hook for data fetching with loading, error, and refetch states using the Fetch API.
Best for: API data fetching
#hooks#fetch
typescriptbeginner
useDebounce — Debounced Value Hook
Debounce any rapidly-changing value with a configurable delay. Useful for search inputs and resize handlers.
Best for: Search-as-you-type
#hooks#debounce