brackt/app/hooks/useFocusTrap.ts

32 lines
1.2 KiB
TypeScript
Raw Normal View History

import { useEffect, type RefObject } from "react";
const FOCUSABLE_SELECTOR =
'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
export function useFocusTrap(ref: RefObject<HTMLElement | null>, active: boolean) {
useEffect(() => {
if (!active) return;
const el = ref.current;
if (!el) return;
const first = el.querySelector<HTMLElement>(FOCUSABLE_SELECTOR) ?? el;
first.focus();
function onKeyDown(e: KeyboardEvent) {
if (e.key !== "Tab") return;
const focusables = Array.from(el?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR) ?? []);
if (focusables.length === 0) return;
const firstEl = focusables[0];
const lastEl = focusables[focusables.length - 1];
if (e.shiftKey) {
if (document.activeElement === firstEl) { e.preventDefault(); lastEl.focus(); }
} else {
if (document.activeElement === lastEl) { e.preventDefault(); firstEl.focus(); }
}
}
document.addEventListener("keydown", onKeyDown);
return () => document.removeEventListener("keydown", onKeyDown);
}, [ref, active]);
}