Introducing PrimeReact v11-alpha 🎉Discover Now

FocusTrap

Headless hook for trapping keyboard focus within a container element.

Register
basic-demo

Usage#

import { useFocusTrap } from '@primereact/headless/focustrap';
 
const { containerRef, firstHiddenElementRef, lastHiddenElementRef, firstHiddenProps, lastHiddenProps } = useFocusTrap();
 
return (
    <>
        <span ref={firstHiddenElementRef} tabIndex={0} {...firstHiddenProps} className="sr-only" />
        <div ref={containerRef}></div>
        <span ref={lastHiddenElementRef} tabIndex={0} {...lastHiddenProps} className="sr-only" />
    </>
);

useFocusTrap manages focus cycling, escape key handling, and auto-focus within a container — see Primitive for a component-based API.

Features#

  • containerRef, firstHiddenElementRef, and lastHiddenElementRef for wiring the trap boundaries
  • firstHiddenProps and lastHiddenProps return spread-ready sentinel props with role="presentation" and aria-hidden
  • Auto-focus on mount: prioritizes initialFocusRef, then [autofocus]/[data-autofocus], then first focusable element
  • MutationObserver watches for DOM changes and refocuses when children are added or removed

Behavior#

Trapped#

Set trapped to false to disable focus cycling. Defaults to true.

const focustrap = useFocusTrap({ trapped: false });

Auto Focus#

Set autoFocus to false to prevent automatic focus on mount. Defaults to true.

const focustrap = useFocusTrap({ autoFocus: false });

Initial Focus#

Pass initialFocusRef to direct focus to a specific element when the trap activates. Takes priority over autoFocus and [autofocus] attribute detection.

const inputRef = React.useRef<HTMLInputElement>(null);
const focustrap = useFocusTrap({ initialFocusRef: inputRef });

Escape Key#

Use onEscape to handle the Escape key press inside the trap.

const focustrap = useFocusTrap({
    onEscape: () => setTrapped(false)
});

Custom Tab Handlers#

Override default focus cycling with onTabFirst and onTabLast callbacks. When provided, these replace the built-in wrap-around behavior.

const focustrap = useFocusTrap({
    onTabFirst: (e) => console.log('Shift+Tab at start'),
    onTabLast: (e) => console.log('Tab at end')
});

Custom Styling with Data Attributes#

The container receives a data-focus-trap attribute when the trap is active.

[data-focus-trap] {
    outline: 2px solid var(--p-primary-color);
}

API#

useFocusTrap#

NameTypeDefault
trappedbooleantrue
When enabled, focus is trapped within the container element.
autoFocusbooleantrue
When enabled, the first focusable element receives focus on mount.
initialFocusRefRefObject<HTMLElement>—
Reference to the element that should receive focus when the trap activates. Takes priority over autoFocus and [autofocus] attribute detection.
onEscape(event: KeyboardEvent) => void—
Callback invoked when the Escape key is pressed inside the trap.
onTabFirst(event: FocusEvent<HTMLElement>) => void—
Callback invoked when Shift+Tab is pressed before the first focusable element. When provided, overrides the default cycling behavior.
onTabLast(event: FocusEvent<HTMLElement>) => void—
Callback invoked when Tab is pressed past the last focusable element. When provided, overrides the default cycling behavior.

Accessibility#

See FocusTrap Primitive for WAI-ARIA compliance details and keyboard support.