JAVASCRIPT
Accessibility-Friendly Focus Trap with useFocusTrap Hook
Implement an accessible focus trap within any React component (e.g., modals) to keep keyboard focus confined, enhancing user experience.
import { useEffect, useCallback, useRef } from 'react';
function useFocusTrap(isActive) {
const trapRef = useRef(null);
const handleKeyDown = useCallback((event) => {
if (!isActive || event.key !== 'Tab') {
return;
}
const focusableElements = trapRef.current.querySelectorAll(
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (!firstElement || !lastElement) {
return; // No focusable elements
}
if (event.shiftKey) { // Shift + Tab
if (document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
}
} else { // Tab
if (document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
}, [isActive]);
useEffect(() => {
if (isActive && trapRef.current) {
trapRef.current.focus(); // Optionally focus the trap container itself or a specific element
document.addEventListener('keydown', handleKeyDown);
} else if (trapRef.current) {
document.removeEventListener('keydown', handleKeyDown);
}
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [isActive, handleKeyDown]);
return trapRef;
}
How it works: The `useFocusTrap` hook helps create an accessible user experience by ensuring that keyboard focus remains within a designated element, typically a modal or dialog. When active, it listens for Tab key presses and redirects focus from the last focusable element back to the first, and vice-versa for Shift+Tab, preventing users from tabbing outside the trapped area.