` 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 any of these.
- 💬 If `initialFocus` is `false` (or a function that returns `false`), this function will not be called when the trap is activated, and no element will be initially focused. This function may still be called while the trap is active if things change such that there are no longer any tabbable nodes in the trap.
- ⚠️ See warning below about **Shadow DOM** and selector strings.
- **escapeDeactivates** `{boolean} | (e: KeyboardEvent) => boolean)`: Default: `true`. If `false` or returns `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. Note that if a function is given, it's only called if the ESC key was pressed.
- **clickOutsideDeactivates** `{boolean | (e: MouseEvent | TouchEvent) => boolean}`: If `true` or returns `true`, a click outside the focus trap will immediately deactivate the focus trap and allow the click event to do its thing (i.e. to pass-through to the element that was clicked). This option **takes precedence** over `allowOutsideClick` when it's set to `true`. Default: `false`.
- 💬 If a function is provided, it will be called up to **twice** (but only if the click occurs *outside* the trap's containers): First on the `mousedown` (or `touchstart` on mobile) event and, if `true` was returned, again on the `click` event. It will get the same node each time, and it's recommended that the returned value is also the same each time. Be sure to check the event type if the double call is an issue in your code.
- ⚠️ If you're using a password manager such as 1Password, where the app adds a clickable icon to all fillable fields, you should avoid using this option, and instead use the `allowOutsideClick` option to better control exactly when the focus trap can be deactivated. The clickable icons are usually positioned absolutely, floating on top of the fields, and therefore *not* part of the container the trap is managing. When using the `clickOutsideDeactivates` option, clicking on a field's 1Password icon will likely cause the trap to be unintentionally deactivated.
- **allowOutsideClick** `{boolean | (e: MouseEvent | TouchEvent) => boolean}`: If set and is or returns `true`, a click outside the focus trap will not be prevented (letting focus temporarily escape the trap, without deactivating it), even if `clickOutsideDeactivates=false`. Default: `false`.
- 💬 If this is a function, it will be called up to **twice** on every click (but only if the click occurs *outside* the trap's containers): First on `mousedown` (or `touchstart` on mobile), and then on the actual `click` if the function returned `true` on the first event. Be sure to check the event type if the double call is an issue in your code.
- 💡 When `clickOutsideDeactivates=true`, this option is **ignored** (i.e. if it's a function, it will not be called).
- Use this option to control if (and even which) clicks are allowed outside the trap in conjunction with `clickOutsideDeactivates=false`.
- **returnFocusOnDeactivate** `{boolean}`: Default: `true`. If `false`, when the trap is deactivated, focus will *not* return to the element that had focus before activation.
- **setReturnFocus** `{HTMLElement | SVGElement | string | (previousActiveElement: HTMLElement | SVGElement) => HTMLElement | SVGElement | string | false}`: By default, on **deactivation**, if `returnFocusOnDeactivate=true` (or if `returnFocus=true` in the [deactivation options](#trapdeactivatedeactivateoptions)), focus will be returned to the element that was focused just before activation. With this option, you can specify another element to programmatically receive focus after deactivation. It can be a DOM node, a selector string (which will be passed to `document.querySelector()` to find the DOM node **upon deactivation**), or a function that returns any of these to call **upon deactivation** (i.e. the selector and function options are only executed at the time the trap is deactivated). Can also be `false` (or return `false`) to leave focus where it is at the time of deactivation.
- 💬 Using the selector or function options is a good way to return focus to a DOM node that may not exist at the time the trap is activated.
- ⚠️ See warning below about **Shadow DOM** and selector strings.
- **preventScroll** `{boolean}`: By default, focus() will scroll to the element if not in viewport. It can produce unintended effects like scrolling back to the top of a modal. If set to `true`, no scroll will happen.
- **delayInitialFocus** `{boolean}`: Default: `true`. Delays the autofocus to the next execution frame when the focus trap is activated. This prevents elements within the focusable element from capturing the event that triggered the focus trap activation.
- **document** {Document}: Default: `window.document`. Document where the focus trap will be active. This allows to use FocusTrap in an iFrame context.
- **tabbableOptions**: (optional) [tabbable options](https://github.com/focus-trap/tabbable#common-options) configurable on FocusTrap (all the *common options*).
- ⚠️ See notes about **[testing in JSDom](#testing-in-jsdom)** (e.g. using Jest).
#### Shadow DOM
##### Selector strings
⚠️ Beware that putting a focus-trap **inside** an open Shadow DOM means you must either:
- **Not use selector strings** for options that support these (because nodes inside Shadow DOMs, even open shadows, are not visible via `document.querySelector()`); OR
- You must **use the `document` option** to configure the focus trap to use your *shadow host* element as its document. The downside of this option is that, while selector queries on nodes inside your trap will now work, the trap will not prevent focus from being set on nodes outside your Shadow DOM, which is the same drawback as putting a focus trap [inside an iframe](https://focus-trap.github.io/focus-trap/#demo-in-iframe).
##### Closed shadows
If you have closed shadow roots that you would like considered for tabbable/focusable nodes, use the `tabbableOptions.getShadowRoot` option to provide Tabbable (used internally) with a reference to a given node's shadow root so that it can be searched for candidates.
### trap.active
```typescript
trap.active: boolean
```
True if the trap is currently active.
### trap.paused
```typescript
trap.paused: boolean
```
True if the trap is currently paused.
### trap.activate()
```typescript
trap.activate([activateOptions]) => FocusTrap
```
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`
- The first tabbable node in the trap
- `createOptions.fallbackFocus`
If none of the above exist, an error will be thrown. You cannot have a focus trap that lacks focus.
Returns the `trap`.
`activateOptions`:
These options are used to override the focus trap's default behavior for this particular activation.
- **onActivate** `{() => void}`: Default: whatever you chose for `createOptions.onActivate`. `null` or `false` are the equivalent of a `noop`.
- **onPostActivate** `{() => void}`: Default: whatever you chose for `createOptions.onPostActivate`. `null` or `false` are the equivalent of a `noop`.
- **checkCanFocusTrap** `{(containers: Array
) => Promise}`: Default: whatever you chose for `createOptions.checkCanFocusTrap`.
### trap.deactivate()
```typescript
trap.deactivate([deactivateOptions]) => FocusTrap
```
Deactivates the focus trap.
Returns the `trap`.
`deactivateOptions`:
These options are used to override the focus trap's default behavior for this particular deactivation.
- **returnFocus** `{boolean}`: Default: whatever you set for `createOptions.returnFocusOnDeactivate`. If `true`, then the `setReturnFocus` option (specified when the trap was created) is used to determine where focus will be returned.
- **onDeactivate** `{() => void}`: Default: whatever you set for `createOptions.onDeactivate`. `null` or `false` are the equivalent of a `noop`.
- **onPostDeactivate** `{() => void}`: Default: whatever you set for `createOptions.onPostDeactivate`. `null` or `false` are the equivalent of a `noop`.
- **checkCanReturnFocus** `{(trigger: HTMLElement | SVGElement) => Promise}`: Default: whatever you set for `createOptions.checkCanReturnFocus`. Not called if the `returnFocus` option is falsy. `trigger` is either the originally focused node prior to activation, or the result of the `setReturnFocus` configuration option.
### trap.pause()
```typescript
trap.pause() => FocusTrap
```
Pause an active focus trap's event listening without deactivating the trap.
If the focus trap has not been activated, nothing happens.
Returns the `trap`.
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.
### trap.unpause()
```typescript
trap.unpause() => FocusTrap
```
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 `trap`.
### trap.updateContainerElements()
```typescript
trap.updateContainerElements() => FocusTrap
```
Update the element(s) that are used as containers for the focus trap.
When you call the function `createFocusTrap`, you pass in an element (or selector), or an array of elements (or selectors) to keep the focus within. This method simply allows you to update which elements to keep the focus within.
A use case for this is found in focus-trap-react, where React `ref`'s may not be initialized yet, but when they are you want to have them be a container element.
Returns the `trap`.
## Examples
Read code in `docs/` and [see how it works](http://focus-trap.github.io/focus-trap/).
Here's generally what happens in `default.js` (the "default behavior" demo):
```js
const { createFocusTrap } = require('../../index');
const container = document.getElementById('default');
const focusTrap = createFocusTrap('#default', {
onActivate: () => container.classList.add('is-active'),
onDeactivate: () => container.classList.remove('is-active'),
});
document
.getElementById('activate-default')
.addEventListener('click', focusTrap.activate);
document
.getElementById('deactivate-default')
.addEventListener('click', focusTrap.deactivate);
```
## Other details
### One at a time
*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.
### Use predictable elements for the first and last tabbable elements in your trap
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](https://github.com/focus-trap/tabbable). You can read about more details [in the Tabbable documentation](https://github.com/focus-trap/tabbable#more-details).
### Your trap should include a tabbable element or a focusable container
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.
## Development
Because of the nature of the functionality, involving keyboard and click and (especially) focus events, JavaScript unit tests don't make sense. After all, JSDom does not fully support focus events. Since the demo was developed to also be the test, we use Cypress to automate running through all demos in the demo page.
## Help
### Testing in JSDom
> ⚠️ JSDom is not officially supported. Your mileage may vary, and tests may break from one release to the next (even a patch or minor release).
>
> This topic is just here to help with what we know may affect your tests.
In general, a focus trap is best tested in a full browser environment such as Cypress, Playwright, or Nightwatch where a full DOM is available.
Sometimes, that's not entirely desirable, and depending on what you're testing, you may be able to get away with using JSDom (e.g. via Jest), but you'll have to configure your traps using the `tabbableOptions.displayCheck: 'none'` option.
See [Testing tabbable in JSDom](https://github.com/focus-trap/tabbable#testing-in-jsdom) for more details.
# Contributing
See [CONTRIBUTING](CONTRIBUTING.md).
## Contributors
In alphabetical order: