REACT FOCUS LOCK

it-is-a-trap - browser friendly focus lock
- matching all your use cases
- trusted by best UI frameworks
- the thing Admiral Ackbar was talking about

[![CircleCI status](https://img.shields.io/circleci/project/github/theKashey/react-focus-lock/master.svg?style=flat-square)](https://circleci.com/gh/theKashey/react-focus-lock/tree/master) [![npm](https://img.shields.io/npm/v/react-focus-lock.svg)](https://www.npmjs.com/package/react-focus-lock) [![bundle size](https://badgen.net/bundlephobia/minzip/react-focus-lock)](https://bundlephobia.com/result?p=react-focus-lock) [![downloads](https://badgen.net/npm/dm/react-focus-lock)](https://www.npmtrends.com/react-focus-lock)
It is a trap! We got your focus and will not let him out! - Modal dialogs. You can not leave it with "Tab", ie do a "tab-out". - Focused tasks. It will aways brings you back, as you can "lock" user inside a component. - Any any other case, when you have to lock user _intention_ and _focus_, if that's what `a11y` is asking for. - Including programatic focus management and smart return focus ### Trusted Trusted by [Atlassian AtlasKit](https://atlaskit.atlassian.com), [ReachUI](https://ui.reach.tech/), [SmoothUI](https://smooth-ui.smooth-code.com/), [Storybook](https://storybook.js.org/) and we will do our best to earn your trust too! # Features - no keyboard control, everything is done watching a __focus behavior__, not emulating it. Focus-Locks works for all cases including positive tab indexes. - React __Portals__ support. Even if some data is in outer space - it is [still in lock](https://github.com/theKashey/react-focus-lock/issues/19). - _Scattered_ locks, or focus lock groups - you can setup different isolated locks, and _tab_ from one to another. - Controllable isolation level. - variable size bundle. Uses _sidecar_ to trim UI part down to 1.5kb. > 💡 __focus__ locks is part of a bigger whole, consider __scroll lock__ and __text-to-speech__ lock you have to use to really "lock" the user. Try [react-focus-on](https://github.com/theKashey/react-focus-on) to archive everything above, assembled in the right order. # How to use Just wrap something with focus lock, and focus will be `moved inside` on mount. ```js import FocusLock from 'react-focus-lock'; const JailForAFocus = ({onClose}) => ( You can not leave this form // is the same as ``` If there is more than one auto-focusable target - the first will be selected. If it is a part of radio group, and __rest of radio group element are also autofocusable__(just put them into AutoFocusInside) - checked one fill be selected. `AutoFocusInside` will work only on Lock activation, and does nothing, then used outside of the lock. You can use `MoveFocusInside` to move focus inside with or without lock. ```js import { MoveFocusInside } from 'react-focus-lock'; ``` # Portals Use focus scattering to handle portals - using `groups`. Just create a few locks (only one could be active) with a same group name ```js const PortaledElement = () => ( // "discoverable" portaled content ); // main content ``` - using `shards`. Just pass all the pieces to the "shards" prop. ```js const PortaledElement = () => (
// "discoverable" portaled content
); // main content ``` - without anything. FocusLock will not prevent focusing portaled element, but will not include them in to tab order ```js const PortaledElement = () => (
// NON-"discoverable" portaled content
); // main content ``` ### Using your own `Components` You may use `as` prop to change _what_ Focus-Lock will render around `children`. ```js Hello there! ``` ### Programmatic Control Let's take a look at the `Rowing Focus` as an example. ```tsx // Will set tabindex to -1 when is not focused const FocusTrackingButton = ({ children }) => { const { active, onFocus, ref } = useFocusState(); return ( ); }; const RowingFocusInternalTrap = () => { const { autoFocus, focusNext, focusPrev } = useFocusScope(); // use useFocusController(divRef) if there is no FocusLock around useEffect(() => { autoFocus(); }, []); const onKey = (event) => { if (event.key === 'ArrowDown') { focusNext({ onlyTabbable: false }); } if (event.key === 'ArrowUp') { focusPrev({ onlyTabbable: false }); } }; return (
Button1 Button2 Button3 Button4
); }; // FocusLock, even disabled one const RowingFocusTrap = () => ( ); ``` ### Guarding As you may know - FocusLock is adding `Focus Guards` before and after lock to remove some side effects, like page scrolling. But `shards` will not have such guards, and it might be not so cool to use them - for example if no `tabbable` would be defined after shard - you will tab to the browser chrome. You may wrap shard with `InFocusGuard` or just drop `InFocusGuard` here and there - that would solve the problem. ```js import {InFocusGuard} from 'react-focus-lock'; // wrap with