data-focus-trap

Constrain keyboard focus within a container. Tab/Shift+Tab cycle inside the boundary, focus auto-moves in on activation, and restores on deactivation.

Overview

The data-focus-trap attribute constrains keyboard focus within a container. Tab and Shift+Tab cycle through focusable children without escaping. When the trap activates, focus moves into the container. When the trap deactivates, focus returns to the previously focused element.

Designed for non-modal panels, inline editing regions, and dynamically inserted content where the native <dialog> focus trap is not available.

How It Works

  1. Activation: When a [data-focus-trap] element enters the DOM (or the attribute is added), focus moves to [autofocus] inside the container, or the first focusable child. The previously focused element is saved.
  2. Trapping: Pressing Tab on the last focusable child wraps to the first. Pressing Shift+Tab on the first wraps to the last.
  3. Deactivation: When the element is removed from the DOM (or the attribute is removed), focus restores to the saved element.

Values

Value Behavior
"" (empty/default) Trap focus and auto-focus [autofocus] or first focusable child on activation.
no-autofocus Trap focus but do not move focus on activation. Useful for toolbars or panels that should trap once the user tabs in.

Dynamic Content

The trap watches the DOM with a MutationObserver. Adding a data-focus-trap element dynamically activates it immediately. Removing the element restores focus automatically.

Toggling via Attribute

You can also activate and deactivate a trap by adding or removing the attribute on an existing element:

JavaScript API

The module exports functions for programmatic control:

Keyboard

Key Action
Tab Move to next focusable child. Wraps from last to first.
Shift + Tab Move to previous focusable child. Wraps from first to last.

Accessibility

  • Focus trapping prevents keyboard users from reaching content behind an active panel.
  • Focus restoration ensures users return to their original context when the panel closes.
  • The [autofocus] integration provides immediate keyboard access to the primary input.
  • Use aria-label or a heading inside the trap to give screen reader context about the trapped region.

When to Use

  • Non-modal slide panels: Settings or filter panels opened with show() (not showModal()).
  • Inline editing: Forms that appear in-page and should capture keyboard focus.
  • Toolbars: Rich text or formatting toolbars with no-autofocus.
  • Dynamic content: Panels loaded via fetch or template insertion.

When Not to Use

  • Modal dialogs: Use <dialog> with showModal() instead — it traps focus natively.
  • Popovers: Popover content typically uses light-dismiss, not focus trapping.
  • Page sections: Don’t trap focus in regular content regions — users expect free navigation.

Related

  • autofocus — Native one-shot focus on page load.
  • tabindex — Control tab order and focusability.
  • <dialog> — Native modal with built-in focus trapping.