import { useEffect, useRef } from 'react'; interface UseFocusTrapOptions { isActive: boolean; onEscape?: () => void; restoreFocus?: boolean; } export function useFocusTrap({ isActive, onEscape, restoreFocus = true, }: UseFocusTrapOptions) { const containerRef = useRef(null); const previousActiveElement = useRef(null); useEffect(() => { if (!isActive || !containerRef.current) return; // Store the element that had focus before modal opened previousActiveElement.current = document.activeElement as HTMLElement; const container = containerRef.current; // Get all focusable elements const getFocusableElements = () => { return container.querySelectorAll( 'button:not(:disabled), [href], input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"]):not(:disabled)' ); }; // Focus first element const focusableElements = getFocusableElements(); const firstElement = focusableElements[0]; if (firstElement) { firstElement.focus(); } // Handle Tab key to trap focus const handleKeyDown = (e: KeyboardEvent) => { // Handle Escape if (e.key === 'Escape' && onEscape) { onEscape(); return; } // Handle Tab if (e.key === 'Tab') { const focusableElements = getFocusableElements(); const firstElement = focusableElements[0]; const lastElement = focusableElements[focusableElements.length - 1]; if (e.shiftKey) { // Shift+Tab if (document.activeElement === firstElement) { lastElement?.focus(); e.preventDefault(); } } else { // Tab if (document.activeElement === lastElement) { firstElement?.focus(); e.preventDefault(); } } } }; container.addEventListener('keydown', handleKeyDown); // Cleanup return () => { container.removeEventListener('keydown', handleKeyDown); // Restore focus to previous element if (restoreFocus && previousActiveElement.current) { previousActiveElement.current.focus(); } }; }, [isActive, onEscape, restoreFocus]); return containerRef; }