Skip to content

Instantly share code, notes, and snippets.

@asvny
Created October 26, 2018 04:55
Show Gist options
  • Save asvny/99988385aa5b1573be49309bbaa0f588 to your computer and use it in GitHub Desktop.
Save asvny/99988385aa5b1573be49309bbaa0f588 to your computer and use it in GitHub Desktop.
FocusTrap - React Hook
// Based on https://hiddedevries.nl/en/blog/2017-01-29-using-javascript-to-trap-focus-in-an-element
import React, { useRef, useEffect } from 'react';
const KEYCODE_TAB = 9;
function useFocusTrap() {
const elRef = useRef(null);
function handleFocus(e) {
var focusableEls = elRef.current.querySelectorAll(
'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select'
),
firstFocusableEl = focusableEls[0],
lastFocusableEl = focusableEls[focusableEls.length - 1];
var isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;
if (!isTabPressed) {
return;
}
if (e.shiftKey) {
/* shift + tab */ if (document.activeElement === firstFocusableEl) {
lastFocusableEl.focus();
e.preventDefault();
}
} /* tab */ else {
if (document.activeElement === lastFocusableEl) {
firstFocusableEl.focus();
e.preventDefault();
}
}
}
useEffect(() => {
elRef.current.addEventListener('keydown', handleFocus);
return _ => {
elRef.current.removeEventListener('keydown', handleFocus);
};
}, []);
return elRef;
}
export default function FocusTrap(props) {
const elRef = useFocusTrap();
return (
<div className={'trap'} ref={elRef}>
{props.children}
</div>
);
}
/// EXAMPLE
/*
<FocusTrap>
<div role="dialog">
<p>
Here is a focus trap
<a href="#">with</a>
<a href="#">some</a>
<a href="#">focusable</a>
parts.
</p>
<p>
<label htmlFor="focused-input" style={{ marginRight: '10px' }}>
Initially focused input
</label>
<input id={'focused-input'} />
</p>
<p>
<button>deactivate trap</button>
</p>
</div>
</FocusTrap>
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment