Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
focus-trap
Advanced tools
The focus-trap npm package is designed to trap focus within a specified DOM element. This is particularly useful for accessibility in modal dialogs, ensuring that keyboard users do not accidentally move focus outside of the dialog, thereby improving the user experience and accessibility compliance.
Create and activate a focus trap
This code demonstrates how to create and activate a focus trap within a specified DOM element, typically a modal dialog. It ensures that all keyboard navigation remains within the 'modal' element.
const { createFocusTrap } = require('focus-trap');
const container = document.getElementById('modal');
const focusTrap = createFocusTrap(container);
focusTrap.activate();
Deactivate a focus trap
This code snippet shows how to deactivate a previously activated focus trap, allowing focus to move freely outside the trapped container once again.
focusTrap.deactivate();
Set return focus on deactivation
This feature allows setting a specific element to receive focus when the focus trap is deactivated. It enhances usability by returning focus to a logical location, such as a button that initially triggered the modal.
const focusTrap = createFocusTrap(container, {
onDeactivate: () => document.getElementById('triggerButton').focus()
});
focus-lock is similar to focus-trap in that it also provides functionality to trap focus within a DOM element. However, focus-lock offers additional features such as auto-focusing the first focusable element and integration with React components.
react-focus-lock is a React-specific implementation of focus trapping. It provides similar functionalities to focus-trap but is tailored specifically for use within React applications, making it easier to integrate with React component lifecycle.
SEEKING CO-MAINTAINERS! Continued development of this project is going to require the work of one or more dedicated co-maintainers (or forkers). If you're interested, please comment in this issue.
Trap focus within a DOM node.
There may come a time when you find it important to trap focus within a DOM node — so that when a user hits Tab
or Shift+Tab
or clicks around, she can't escape a certain cycle of focusable elements.
You will definitely face this challenge when you are trying to build accessible modals.
This module is a little, modular vanilla JS solution to that problem.
Use it in your higher-level components. For example, if you are using React check out focus-trap-react, a light wrapper around this library. If you are not a React user, consider creating light wrappers in your framework-of-choice.
When a focus trap is activated, this is what should happen:
Tab
and Shift+Tab
keys will cycle through the focus trap's tabbable elements but will not leave the focus trap.Escape
key will deactivate the focus trap.When the focus trap is deactivated, this is what should happen:
For more advanced usage (e.g. focus traps within focus traps), you can also pause a focus trap's behavior without deactivating it entirely, then unpause at will.
npm install focus-trap
You can also use a UMD version published to unpkg.com
as dist/focus-trap.js
and dist/focus-trap.min.js
.
IE9+
Why?
Because this module uses EventTarget.addEventListener()
.
And its only dependency, tabbable, uses a couple of IE9+ functions.
import { createFocusTrap } from 'focus-trap'; // ESM
const { createFocusTrap } = require('focus-trap'); // CJS
focusTrap = createFocusTrap(element[, createOptions]);
Returns a new focus trap on element
.
element
can be
document.querySelector()
to find the DOM node).createOptions
:
document.querySelector()
to find the DOM node), or a function that returns a DOM node.<div>
to receive focus if the popover's content includes no tabbable elements. Make sure the fallback element has a negative tabindex
so it can be programmatically focused. The option value can be a DOM node, a selector string (which will be passed to document.querySelector()
to find the DOM node), or a function that returns a DOM node.true
. If false
, the Escape
key will not trigger deactivation of the focus trap. This can be useful if you want to force the user to make a decision instead of allowing an easy way out.false
. If true
, a click outside the focus trap will deactivate the focus trap and allow the click event to do its thing.true
. If false
, when the trap is deactivated, focus will not return to the element that had focus before activation.document.querySelector()
to find the DOM node), or a function that returns a DOM node.true
, a click outside the focus trap will not be prevented, even when clickOutsideDeactivates
is false
.true
, no scroll will happen.Activates the focus trap, adding various event listeners to the document.
If focus is already within it the trap, it remains unaffected. Otherwise, focus-trap will try to focus the following nodes, in order:
createOptions.initialFocus
createOptions.fallbackFocus
If none of the above exist, an error will be thrown. You cannot have a focus trap that lacks focus.
Returns the focusTrap
.
activateOptions
:
These options are used to override the focus trap's default behavior for this particular activation.
createOptions.onActivate
. null
or false
are the equivalent of a noop
.Deactivates the focus trap.
Returns the focusTrap
.
deactivateOptions
:
These options are used to override the focus trap's default behavior for this particular deactivation.
createOptions.returnFocusOnDeactivate
.createOptions.onDeactivate
. null
or false
are the equivalent of a noop
.Pause an active focus trap's event listening without deactivating the trap.
If the focus trap has not been activated, nothing happens.
Returns the focusTrap
.
Any onDeactivate
callback will not be called, and focus will not return to the element that was focused before the trap's activation. But the trap's behavior will be paused.
This is useful in various cases, one of which is when you want one focus trap within another. demo-six
exemplifies how you can implement this.
Unpause an active focus trap. (See pause()
, above.)
Focus is forced into the trap just as described for focusTrap.activate()
.
If the focus trap has not been activated or has not been paused, nothing happens.
Returns the focusTrap
.
Read code in demo/
and see how it works.
Here's what happens in default.js
(the "default behavior" demo):
var { createFocusTrap } = require('../../dist/focus-trap');
var container = document.getElementById('default');
var focusTrap = createFocusTrap('#default', {
onActivate: function () {
container.className = 'trap is-active';
},
onDeactivate: function () {
container.className = 'trap';
},
});
document
.getElementById('activate-default')
.addEventListener('click', function () {
focusTrap.activate();
});
document
.getElementById('deactivate-default')
.addEventListener('click', function () {
focusTrap.deactivate();
});
Only one focus trap can be listening at a time. If a second focus trap is activated the first will automatically pause. The first trap is unpaused and again traps focus when the second is deactivated.
Focus trap manages a queue of traps: if A activates; then B activates, pausing A; then C activates, pausing B; when C then deactivates, B is unpaused; and when B then deactivates, A is unpaused.
The focus trap will work best if the first and last focusable elements in your trap are simple elements that all browsers treat the same, like buttons and inputs.**
Tabbing will work as expected with trickier, less predictable elements — like iframes, shadow trees, audio and video elements, etc. — as long as they are between more predictable elements (that is, if they are not the first or last tabbable element in the trap).
This limitation is ultimately rooted in browser inconsistencies and inadequacies, but it comes to focus-trap through its dependency Tabbable. You can read about more details in the Tabbable documentation.
You can't have a focus trap without focus, so an error will be thrown if you try to initialize focus-trap with an element that contains no tabbable nodes.
If you find yourself in this situation, you should give you container tabindex="-1"
and set it as initialFocus
or fallbackFocus
. A couple of demos illustrate this.
Because of the nature of the functionality, involving keyboard and click and (especially) focus events, JavaScript unit tests didn't make sense. (If you disagree and can help out, please PR!) So the demo is also the test: run it in browsers and see how it works, checking the documented requirements.
6.0.1
FAQs
Trap focus within a DOM node.
The npm package focus-trap receives a total of 1,675,416 weekly downloads. As such, focus-trap popularity was classified as popular.
We found that focus-trap demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.