react-widgets
Version:
An à la carte set of polished, extensible, and accessible inputs built for React
40 lines (33 loc) • 1.22 kB
JavaScript
import { useMemo, useRef } from 'react';
import useEventListener from '@restart/hooks/useEventListener';
const defaultSelector = ['input', 'textarea', 'select', 'button:not([tabindex="-1"])', '[tabindex="0"]'].join(',');
const getDocument = () => document;
export default function useTabTrap(ref, selector = defaultSelector) {
const startedRef = useRef(false);
useEventListener(getDocument, 'keydown', event => {
if (!startedRef.current || !ref.current || event.key !== 'Tab') {
return;
}
const tabbables = ref.current.querySelectorAll(selector);
if (event.shiftKey && event.target === tabbables[0]) {
tabbables[tabbables.length - 1].focus();
event.preventDefault();
} else if (!event.shiftKey && event.target === tabbables[tabbables.length - 1] || !ref.current.contains(event.target)) {
tabbables[0].focus();
event.preventDefault();
}
});
return useMemo(() => ({
focus() {
const tabbables = ref.current.querySelectorAll(selector);
const first = tabbables[0];
if (first) first.focus();
},
start() {
startedRef.current = true;
},
stop() {
startedRef.current = false;
}
}), [ref, selector]);
}