What is react-focus-lock?
The react-focus-lock package is a React component designed to trap focus within a DOM element. It is commonly used to ensure that keyboard users can navigate modal dialogs and other pop-up UI elements without accidentally interacting with the rest of the page.
What are react-focus-lock's main functionalities?
Focus Trapping
This feature traps the focus within the modal dialog. When the modal is open, the focus cycles through the interactive elements inside the modal and does not move to the background elements.
{"import React from 'react';\nimport FocusLock from 'react-focus-lock';\n\nconst Modal = ({ onClose }) => (\n <FocusLock>\n <div className='modal'>\n <button onClick={onClose}>Close</button>\n {/* other modal contents */}\n </div>\n </FocusLock>\n);"}
AutoFocus and Return Focus
This feature automatically focuses the first focusable element within the FocusLock on mount and returns the focus to the initially focused element when the FocusLock is unmounted.
{"import React from 'react';\nimport FocusLock from 'react-focus-lock';\n\nconst Modal = ({ onClose }) => (\n <FocusLock autoFocus={true} returnFocus={true}>\n <div className='modal'>\n <button onClick={onClose}>Close</button>\n {/* other modal contents */}\n </div>\n </FocusLock>\n);"}
Focus Grouping
This feature allows grouping of focusable elements. Focus can be moved inside a group, and it will be contained within the elements of that group.
{"import React from 'react';\nimport FocusLock, { MoveFocusInside } from 'react-focus-lock';\n\nconst Group = () => (\n <div>\n <MoveFocusInside>\n <button>Button1</button>\n </MoveFocusInside>\n <MoveFocusInside>\n <button>Button2</button>\n </MoveFocusInside>\n </div>\n);\n\nconst App = () => (\n <FocusLock group='group1'>\n <Group />\n </FocusLock>\n);"}
Other packages similar to react-focus-lock
react-modal
react-modal is a package that provides accessible modals for React applications. It includes the ability to trap focus within the modal, similar to react-focus-lock, but it is specifically designed for modal dialog creation and management.
react-aria-modal
react-aria-modal is a fully accessible React modal component that manages focus. It also traps focus within the modal, similar to react-focus-lock, and provides a comprehensive solution for creating accessible modals with ARIA attributes.
react-trap-focus
react-trap-focus is a package that provides focus trapping functionality. It is similar to react-focus-lock in that it traps focus within a specified element, but it may have different implementation details or additional features.
REACT FOCUS LOCK
The way to manage your focus.
The way to lock it inside.
The way to team up with a11y.
Make you site a better place. For everyone.
It is a trap! We got your focus and will not let him out!
This is a small library, but very useful for:
- 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.
You have to lock every modal dialog, that's what a11y
is asking for.
And this is most comprehensive focus lock/trap ever built.
Features
- no keyboard control, everything is done watching a focus behavior, not emulating tabs. Thus works always and everywhere.
- React Portals support. Even if some data is in outerspace - it is still in lock.
- Scattered locks, or focus lock groups - you can setup different isolated locks, and tab from one to another.
- Controllable isolation level.
How to use
Just wrap something with focus lock, and focus will be moved inside
on mount.
import FocusLock from 'react-focus-lock';
const JailForAFocus = ({onClose}) => (
<FocusLock>
You can not leave this form
<button onClick={onClick} />
</FocusLock>
);
Demo - https://codesandbox.io/s/5wmrwlvxv4.
Final piece for a modals
That is actually not enough, - you shall not lock the focus, but also disable page scroll and user iteractions with the rest of a page - "shadow" rest of the page, to make it unclickable or
unscrollable.
And react-locky is your next component to check.
WHY?
From MDN Article about accessible dialogs:
- The dialog must be properly labeled
- Keyboard focus must be managed correctly
This one is about managing the focus.
I'v got a good article about focus management, dialogs and WAI-ARIA.
API
FocusLock has few props to tune behavior
disabled
, to disable(enable) behavior without altering the tree.returnFocus
, to return focus into initial position on unmount(not disable).
This is expected behavior for Modals, but it is better to implement it by your self.persistentFocus
, default false, requires any element to be focused. This also disables text selections inside, and outside focus lock.autoFocus
, default true, enables or disables focusing into on Lock activation. If disabled Lock will blur an active focus.noFocusGuards
disabled focus guards - virtual inputs which secure tab index.group
named focus group for focus scattering aka combined lock targets
Behavior
- It will always keep focus inside Lock.
- It will cycle forward then you press Tab.
- It will cycle in reverse direction on Shift+Tab.
- It will do it using browser tools, not emulation.
- It will handle positive tabIndex inside form.
- It will prevent any jump outside, returning focus to the last element.
Focusing in OSX (Safary/FireFox) is strange!
By default tabbing
in OSX sees
only control, but not links or anything else tabbable
. This is system settings, and Safary/FireFox obey.
Press Option+Tab in Safary to loop across all tabbables, or change the Safary settings. There is no way to fix FireFox, unless change system settings (Control+F7). See this issue for more information.
You can use nested Locks or have more than one Lock on the page.
Only last
, or deepest
one will work. No fighting.
Autofocus
As long you cannot use autoFocus
prop -
cos "focusing" should be delayed to Trap activation, and autoFocus will effect immediately -
Focus Lock provide a special API for it
- prop
data-autofocus
on the element. - prop
data-autofocus-inside
on the element to focus on something inside. AutoFocusInside
component, as named export of this library.
import FocusLock, { AutoFocusInside } from 'focus-lock';
<FocusLock>
<button>Click</button>
<AutoFocusInside>
<button>will be focused</button>
</AutoFocusInside>
</FocusLock>
<FocusLock>
<button>Click</button>
<button data-autofocus>will be focused</button>
</FocusLock>
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 'focus-lock';
<MoveFocusInside>
<button>will be focused</button>
</MoveFocusInside>
Unmounting and focus management
- In case FocusLock has
returnFocus
enabled, and it's gonna to be unmounted - focus will be returned after zero-timeout. - In case
returnFocus
did not set, and you are going to control focus change by your own - keep in mind
React will first call Parent.componentWillUnmount, and next Child.componentWillUnmount
Thus means - Trap will be still active, be the time you may want move(return) focus on componentWillUnmount. Please deffer this action with a zero-timeout.
How it works
Everything thing is simple - react-focus-lock just dont left focus left boundaries of component, and
do something only if escape attempt was succeeded.
It is not altering tabbing behavior at all. We are good citizens.
Not only for React
Uses focus-lock under the hood. It does also provide support for Vue.js and Vanilla DOM solutions
More
Dont forget to lock the scroll to complete the picture.
react-scroll-locky - browser scrollbars hiding, you were looking for.
Warning!
Two different focus-lock-managers or even different version of a single one, active
simultaneously will FIGHT!
Licence
MIT