FocusTrap
Headless hook for trapping keyboard focus within a container element.
Register
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, andlastHiddenElementReffor wiring the trap boundariesfirstHiddenPropsandlastHiddenPropsreturn spread-ready sentinel props withrole="presentation"andaria-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#
| Name | Type | Default |
|---|---|---|
trapped | boolean | true |
| When enabled, focus is trapped within the container element. | ||
autoFocus | boolean | true |
| When enabled, the first focusable element receives focus on mount. | ||
initialFocusRef | RefObject<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.