- Handles edge cases such as hidden or dynamically added elements
- Works with shadow DOM via the
getShadowRootoption - Supports nested focus traps — pauses the outer trap while an inner one is active
- Follows ARIA-controlled elements (e.g., portalled menus opened from within the trap)
- Automatically restores focus to the previously focused element on deactivation
Installation
Usage
trapFocus
The trapFocus function is the primary entry point. Pass an element (or a getter function that returns one), and
it returns a destroy function to release the trap.
Default behavior
By default,trapFocus is configured with sensible defaults:
| Option | Default value |
|---|---|
escapeDeactivates | false |
allowOutsideClick | true |
preventScroll | true |
returnFocusOnDeactivate | true |
delayInitialFocus | false |
Multiple containers
Pass an array of elements to trap focus across multiple container nodes simultaneously.Using the FocusTrap class directly
For advanced use cases — such as pausing and resuming a trap independently — use the FocusTrap class.
Shadow DOM support
Enable shadow DOM traversal with thegetShadowRoot option.
Animated containers
When trapping focus in an element that fades in, usecheckCanFocusTrap to delay activation until the element
is ready to receive focus.
checkCanReturnFocus to delay returning focus to the trigger element when it fades back in.
API reference
trapFocus
destroy function that deactivates the trap and restores focus.
FocusTrap class
FocusTrapOptions
The element to focus when the trap activates. Accepts an
HTMLElement, a CSS selector string, a getter function,
or false to skip initial focus entirely.An element to focus programmatically if no tabbable element is found in the trap. Ensure the element has a
negative
tabindex so it can receive programmatic focus.When
true, focus returns to the element that was focused before the trap was activated.setReturnFocus
HTMLElement | string | ((nodeFocusedBefore: HTMLElement | SVGElement) => HTMLElement | string | false)
Override which element receives focus on deactivation instead of the default previously focused element.
When
true, pressing Escape deactivates the trap. Pass a function for conditional logic.When
true, clicking outside the trap deactivates it and allows the click to pass through.When
true, clicks outside the trap are not prevented, even when clickOutsideDeactivates is false.When
true, the page will not scroll when focusing the initial element.When
true, the initial focus is applied in a setTimeout to avoid capturing the event that triggered trap activation.The document to use. Useful in
<iframe> contexts. Defaults to window.document.Determines if the given keyboard event moves focus forward. Defaults to
Tab.Determines if the given keyboard event moves focus backward. Defaults to
Shift+Tab.An external array for managing multiple nested traps. Defaults to a shared internal stack.
When
true, elements controlled via aria-controls with aria-expanded="true" (such as portalled menus)
are included in the trap’s tabbable scope.Enables shadow DOM traversal. Pass
true for open shadow roots or a function for closed shadow roots.Called during activation. Return a promise that resolves when it is safe to focus the trap container.
Useful for animated elements.
Called during deactivation when returning focus. Return a promise that resolves when the trigger element
is ready to receive focus.
Called before focus is sent to the initial element on activation.
Called after focus has been sent to the initial element on activation.
Called before the trap is deactivated.
Called after the trap is fully deactivated and focus has been restored.
Called immediately after the trap’s state is set to paused.
Called after the trap has finished pausing and is no longer managing focus.
Called immediately after the trap’s state is set back to active.
Called after the trap has fully resumed managing focus.