TrapFocus

_preview example is not found
import { TrapFocus } from "reshaped"

When TrapFocus is activated, it traps keyboard and screen reader navigation within the given element until focus is released. Since TrapFocus is a class, you can create a new instance and pass the target element to initialize it. This is useful when an element (like a modal or popup) appears on screen. When the element is dismissed, call the release method to restore normal focus behavior.

You can manage this behavior inside a useEffect hook:

useEffect(() => {
  const trapFocus = new TrapFocus();

  trapFocus.trap(targetRef.current);
  return () => trapFocus.release();
}, [active])

There are four focus trap modes available. The default mode is dialog, which fully locks keyboard navigation inside the trapped area. It handles Tab and Shift + Tab, looping focus within the element. Use this mode for components like Modal.

dialog example is not found

The action-menu mode is designed for components like action menus and is used internally by DropdownMenu. It allows focus navigation with the ArrowUp and ArrowDown keys. Pressing Tab moves focus to the next element after the original trigger and automatically releases the focus trap. You can use the onRelease option to dismiss the content when that happens.

action-menu example is not found

The action-bar mode works like action-menu, but uses the ArrowLeft and ArrowRight keys to move focus instead.

action-bar example is not found

The content-menu mode is useful for components like navigation menus that contain regular content, such as a list of links. It keeps the navigation flow natural by including all focusable elements in the trapped area after the trigger element. Focus navigation uses the Tab key, but pressing Tab on the last element moves focus to the next element after the original trigger. This releases the focus trap, and you can respond to it using the onRelease handler.

content-menu example is not found

Using includeTrigger adds the original trigger element to the focus sequence.
It also keeps focus on the trigger when the focus trap is initialized.

trapFocus.trap(ref.current, { includeTrigger: true })

Use initialFocusEl to set which element should receive focus when the trap is initialized.

trapFocus.trap(ref.current, {
  initialFocusEl: internalElementRef.current,
})

By default, releasing the focus trap returns focus to the original trigger element.
Use the withoutFocusReturn option to disable this behavior.
This is useful when closing the element with an outside click and you want to avoid the page scrolling back to the trigger.

trapFocus.release({ withoutFocusReturn: true })
{
  trap: (
    el: HTMLElement,
    {
      // Keep the focus on the trigger and include it in the focus sequence
      includeTrigger: boolean,

      // Element to move to the focus to after the initialization
      initialFocusEl: HTMLElement
    }
  ) => void,

  release: (
    options: {
      // Prevent from returning the focus back to the original trigger
      withoutFocusReturn: boolean
    }
  ) => void,

  // State of the focus trap
  active: boolean
}
Professionally crafted React & Figma components for building beautiful products or starting your own design system
Built with Reshaped in Amsterdam ❤️
Contact us·
© Reshaped 2026