Skip to content

Instantly share code, notes, and snippets.

@just-boris
Created May 17, 2022 21:06
Show Gist options
  • Save just-boris/3be2b1cce3d9d65047851f3661fae996 to your computer and use it in GitHub Desktop.
Save just-boris/3be2b1cce3d9d65047851f3661fae996 to your computer and use it in GitHub Desktop.
focus-soft-lock
import React, { useEffect, useRef } from 'react';
// Credits to
// https://github.com/theKashey/focus-lock/blob/33f8b4bd9675d2605b15e2e4015b77fe35fbd6d0/src/utils/tabbables.ts
const tabbables = [
'button:enabled',
'select:enabled',
'textarea:enabled',
'input:enabled',
'a[href]',
'area[href]',
'summary',
'iframe',
'object',
'embed',
'audio[controls]',
'video[controls]',
'[tabindex]',
'[contenteditable]',
'[autofocus]',
].join(',');
function getFocussables(container: HTMLElement) {
return Array.prototype.slice.call(container.querySelectorAll(tabbables));
}
function tryFocusNodes(nodes: ReadonlyArray<HTMLElement>) {
for (const node of nodes) {
node.focus();
if (document.activeElement === node) {
return;
}
}
}
const moveForwards = (container: HTMLElement) => {
tryFocusNodes(getFocussables(container));
};
const moveBackwards = (container: HTMLElement) => {
tryFocusNodes(getFocussables(container).reverse());
};
interface FocusLockProps {
className: string;
children: React.ReactNode;
}
export default function FocusLock({ className, children }: FocusLockProps) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
moveForwards(containerRef.current!);
}, []);
return (
<>
<div tabIndex={0} onFocus={() => moveBackwards(containerRef.current!)}></div>
<div className={className} ref={containerRef}>
{children}
</div>
<div tabIndex={0} onFocus={() => moveForwards(containerRef.current!)}></div>
</>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment