) | undefined;
/**
* By default, when a focus trap is activated the first element in the
* focus trap's tab order will receive focus. With this option you can
* specify a different element to receive that initial focus, or use `false`
* for no initially focused element at all.
*
* NOTE: Setting this option to `false` (or a function that returns `false`)
* will prevent the `fallbackFocus` option from being used.
*
* Setting this option to `undefined` (or a function that returns `undefined`)
* will result in the default behavior.
*/
initialFocus?: FocusTargetOrFalse | undefined | VoidFunction;
/**
* By default, an error will be thrown if the focus trap contains no
* elements in its tab order. With this option you can specify a
* fallback element to programmatically receive focus if no other
* tabbable elements are found. For example, you may want a popover's
* `` 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.
*
* NOTE: 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.
*/
fallbackFocus?: FocusTarget | undefined;
/**
* Default: `true`. If `false`, when the trap is deactivated,
* focus will *not* return to the element that had focus before activation.
*/
returnFocusOnDeactivate?: boolean | undefined;
/**
* By default, focus trap on deactivation will return to the element
* that was focused before activation.
*/
setReturnFocus?: FocusTargetValueOrFalse | ((nodeFocusedBeforeActivation: HTMLElement | SVGElement) => FocusTargetValueOrFalse) | undefined;
/**
* 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.
*/
escapeDeactivates?: boolean | KeyboardEventToBoolean | undefined;
/**
* If `true` or returns `true`, a click outside the focus trap will
* 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`, causing
* that option to be ignored. Default: `false`.
*/
clickOutsideDeactivates?: boolean | MouseEventToBoolean | undefined;
/**
* If set and is or returns `true`, a click outside the focus trap will not
* be prevented, even when `clickOutsideDeactivates` is `false`. When
* `clickOutsideDeactivates` is `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`. Default: `false`.
*/
allowOutsideClick?: boolean | MouseEventToBoolean | undefined;
/**
* 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.
*/
preventScroll?: boolean | undefined;
/**
* Default: `true`. Delays the autofocus when the focus trap is activated.
* This prevents elements within the focusable element from capturing
* the event that triggered the focus trap activation.
*/
delayInitialFocus?: boolean | undefined;
/**
* Default: `window.document`. Document where the focus trap will be active.
* This allows to use FocusTrap in an iFrame context.
*/
document?: Document | undefined;
/**
* Determines if the given keyboard event is a "tab forward" event that will move
* the focus to the next trapped element in tab order. Defaults to the `TAB` key.
* Use this to override the trap's behavior if you want to use arrow keys to control
* keyboard navigation within the trap, for example. Also see `isKeyBackward()` option.
*/
isKeyForward?: KeyboardEventToBoolean | undefined;
/**
* Determines if the given keyboard event is a "tab backward" event that will move
* the focus to the previous trapped element in tab order. Defaults to the `SHIFT+TAB` key.
* Use this to override the trap's behavior if you want to use arrow keys to control
* keyboard navigation within the trap, for example. Also see `isKeyForward()` option.
*/
isKeyBackward?: KeyboardEventToBoolean | undefined;
/**
* Default: `[]`. An array of FocusTrap instances that will be managed by this FocusTrap.
*/
trapStack?: any[] | undefined;
/**
* Default: `true`. If `true`, the focus trap will recursively include elements
* that are controlled by elements within the trap via `aria-controls`. Only elements
* with `aria-expanded="true"` and interactive container roles (menu, listbox, dialog, etc.)
* will be included. This allows nested menus, select dropdowns, and other portalled
* content to remain within the focus trap.
*/
followControlledElements?: boolean | undefined;
/**
* Optional function to support shadow DOM traversal. When provided, it enables
* the focus trap to find tabbable elements inside shadow roots (web components).
*
* - `true`: Enable shadow DOM support for open shadow roots
* - `false` or `undefined`: Disable shadow DOM support (default)
* - Function: Called with each element; return `true` if it has a shadow root to traverse,
* the `ShadowRoot` instance, or a falsy value if no shadow root exists
*
* This is required for proper focus management when using web components or custom elements
* with shadow DOM.
*
* @example
* ```ts
* // Enable for all open shadow roots
* getShadowRoot: true
*
* // Custom function for closed shadow roots
* getShadowRoot: (node) => {
* if (node === myCustomElement) return myCustomElement.shadowRoot
* return node.shadowRoot
* }
* ```
*/
getShadowRoot?: boolean | ((node: FocusableElement) => ShadowRoot | boolean | undefined) | undefined;
/**
* Additional elements to treat as part of the trap, for portalled content
* not discoverable via `aria-controls`/`aria-expanded` (see `followControlledElements`).
*/
persistentElements?: Array<() => Element | null> | undefined;
}
interface ContainerGroup {
container: HTMLElement;
tabbableNodes: FocusableElement[];
focusableNodes: FocusableElement[];
posTabIndexesFound: boolean;
firstTabbableNode: FocusableElement | undefined;
lastTabbableNode: FocusableElement | undefined;
firstDomTabbableNode: FocusableElement | undefined;
lastDomTabbableNode: FocusableElement | undefined;
nextTabbableNode: (node: HTMLElement, forward?: boolean) => FocusableElement | undefined;
}
interface FindNextNodeOptions {
target?: HTMLElement | null | undefined;
event?: FocusEvent | KeyboardEvent | undefined;
isBackward?: boolean | undefined;
}
interface FocusTrapState {
containers: HTMLElement[];
nodeFocusedBeforeActivation: HTMLElement | null;
mostRecentlyFocusedNode: HTMLElement | null;
active: boolean;
paused: boolean;
delayInitialFocusTimer: any;
containerGroups: ContainerGroup[];
tabbableGroups: ContainerGroup[];
recentNavEvent: KeyboardEvent | undefined;
}
interface DeactivateOptions extends Pick {
returnFocus?: boolean | undefined;
}
type ActivateOptions = Pick;
type PauseOptions = Pick;
type UnpauseOptions = Pick;
export type { ActivateOptions, DeactivateOptions, FindNextNodeOptions, FocusTarget, FocusTargetOrFalse, FocusTargetValue, FocusTargetValueOrFalse, FocusTrapOptions, FocusTrapState, FocusableElement, PauseOptions, UnpauseOptions };