focus-trap demo

Return to the repository

In the demos below, you'll be able to tell that a focus trap is active because it will turn pink. You should also be able to tell because it will trap your focus!

When a trap is active, you can deactivate it by pushing its deactivate button or, if the demo allows, pressing the Escape key.

Before you try the demos, if you're using macOS, make sure you have enabled keyboard navigation in order to use the Tab key to move focus between all controls.

In Ventura (v13), you'll find this under System Settings > Keyboard. Prior to Ventura, it may have been under System Settings > General.

FireFox and Safari, for example, respect this setting and without it enabled, you won't get a good experience. Chrome appears to ignore it (at least in v109). While focus-trap will still trap all the right nodes, the browser/OS will not let you access all tabbable nodes on the page, nor in any traps you activate, while using the Tab key.

default behavior

Here is a focus trap with some focusable parts.

View demo source

animated dialog

This focus trap will fade in when activated and fade out when deactivated. Once the trap has been activated (i.e. onPostActivate), a "trap activated" message appears next to the Activate button. Note that the fade animation needs to be written yourself, it is not built into the library.

Here is a focus trap with some focusable parts.

View demo source

animated trigger

The activation button for this focus trap will fade out when the trap activates and fade in when the trap deactivates.

If the returnFocus option is true, the activation button will receive focus after the trap deactivates.

If the returnFocus option is false, the Deactivate button will retain focus after deactivation because that is the last element that was clicked prior to deactivation.

Once the trap has been deactivated (i.e. onPostDeactivate), a "trap deactivated" message appears next to the "returnFocus" option.

Note that the fade animation needs to be written yourself, it is not built into the library.

Here is a focus trap with some focusable parts.

View demo source

configurable escape behavior

This focus trap leverages the escapeDeactivates option as a function rather than a boolean. By default, pressing ESC will deactivate the trap, but while the trap is active, you can check or uncheck the option, and the ESC key will behave accordingly.

Since the escapeDeactivates option received the related KeyboardEvent, it could be used to programmatically decide if the ESC key should allow the trap to be deactivated, perhaps based on the node that's currently focused, or some other condition.

Here is a focus trap with some focusable parts.

View demo source

initial element, no escape

If initialFocus is a selector or DOM node, focus will jump to that specified element when the trap activates.

If initialFocus is false (or a function that returns false), no element will be given focus when the trap activates.

initialFocus is set to the first tabbable element by default.

Also, in this demo the Escape key does not deactivate the focus trap. You must click the button.

Here is a focus trap with some focusable parts.

View demo source

initially focused container

When this focus trap activates, initial focus is on the containing element (which has tabindex="-1" and is therefore not tabbable). When you tab through the trap, focus does not return to the containing element.

Also, clicking on an outside element automatically deactivates this trap.

View demo source

hidden treasures

Focusable nodes are initially hidden and then revealed within the trap.

Use Escape to exit.

View demo source

nested

Nested focus traps.

View demo source

sibling traps

Sibling focus traps. When the second trap is deactivated, focus returns to the first trap.

View demo source

tricky initial focus

In this focus trap, the single focusable button is hidden (the ones you see at first have tabindex="-1"). If you activate the trap in this state, the fallbackFocus option is used to focus the container. If, however, you first make the focusable button visible by clicking "show focusable button", that button will receive focus when you activate the trap.

View demo source

input activation

Any change to the input content triggers automatic activation of the focus trap, without changing selection within the input.

Here is a focus trap with some focusable parts.

View demo source

delay

focus-trap ensure that the placement of focus within the trap is slightly delayed, so the focused element does not capture the event that originated the activation of the focus trap. For example, the same Enter keystroke won't open and close this trap.

View demo source

No delay

focus-trap ensure that the placement of focus within the trap is not delayed, so the focused element captures the event that originated the activation of the focus trap.

View demo source

radio group

A default focus trap that contains a radio group. You should be able to change the radio group with the arrow keys, but Tab should only focus the active radio. (Notice that you need a checked radio in the group for things to work as expected.)

Radio group

View demo source

iframe

This focus trap contains an iframe. You should be able to tab into and out of the iframe. But you need to have a focusable element before and after the iframe for things to work as expected.

View demo source

working inside an iframe

This focus trap can be executed inside an iframe. You should be able to trap the focus inside. You need to have provided the iframe document to the focus-trap before for things to work as expected.

⚠️ As it executes inside the iframe, it cannot prevent clicks on links in the parent document. This is the same drawback as you might experience when putting a focus-trap inside a Shadow DOM.

View demo source

inside an open shadow dom

This focus trap is instantiated inside an open Shadow DOM. Some users of this library use Web Components to create things like modal dialogs, which means focus needs to be trapped inside the Shadow DOM instance.

When the mouse is clicked on an element inside an open Shadow DOM, the target node in event.target is always the shadow host (the node to which the shadow is attached). Fortunately, event.composedPath(), a modern API on the event object, allows focus-trap to determine the actual node that was clicked inside the shadow.

⚠️ focus-trap is unable to work with closed Shadow DOMs because event.composedPath() can't see inside it. In this case, both this modern API and event.target point to the shadow host as the actual element that was clicked, and focus-trap will always determine that the click was outside the trap (and either prevent it, or always deactivate the trap when the clickOutsideDeactivates option is true).

⚠️ See the warning about selector string options when putting a focus trap inside an open Shadow DOM.

View demo source

with shadow dom

This focus trap contains tabbable elements that are inside open and closed Shadow DOMs. It configures tabbable to look for Shadow DOM elements and provides a reference to the closed Shadow when requested.

Here is a focus trap with some focusable parts.

View demo source

allowOutsideClick option

This focus trap can be closed also by clicking a button outside of the trap that is able to control the trap (which is the "activate trap" button in this example). ESC is disabled for this trap.

NOTE: This is different from the clickOutsideDeactivates where merely clicking outside the trap would cause it to be deactivated. In this example, the outside click must take place on the "activate/deactivate trap" button, whose click event handler will programmatically deactivate the trap.

Here is a focus trap with some focusable parts.

View demo source

clickOutsideDeactivates option

This focus trap can be closed simply by clicking anywhere outside, and the click outside will also go through and do what it was intentionally dispatched to do (like toggling the checkbox). ESC is disabled for this trap.

The returnFocusOnDeactivate option controls whether focus should be returned to the last-focused element when the trap was activated (the "activate trap" button in this demo) or not:

Here is a focus trap with some focusable parts.

View demo source

setReturnFocus option

With setReturnFocus it is possible to overwrite the returnFocusElement.

Here is a focus trap with some focusable parts.

View demo source

setReturnFocus as function

As the function is executed in the process of deactivation, it allows you to dynamically specify which element should be focused after deactivation.

Once the trap is activated, you can still click on one of the 3 deactivate buttons below in order to deactivate the trap.

Here is a focus trap with some focusable parts.

View demo source

multiple elements

You can pass multiple elements, and the focus will be kept within those element boundaries (darker color). Clicking outside deactivates.

Here is a focus trap with some focusable parts.

Here is something.

Here is a another focus trap element. See how it works.

View demo source

multiple elements with delete

Pass multiple elements. Update the tabbable nodes in any of those elements on the fly, ensuring there's always at least one container with at least one tabbable node in it at all times.

Container 1

Container 2

Some other focusable parts.

Not in trap (clicks allowed)

View demo source

multiple elements with delete ALL

Pass multiple elements. With the fallbackFocus option configured to the "deactivate trap" button, remove ALL nodes in all trap containers to have the focus fall back to the "deactivate" button on the next tab key press.

Container 1

Container 2

Not in trap (fallback; clicks allowed)

View demo source

multiple traps with multiple elements

You can have multiple traps with multiple elements. Each trap's elements are in a darker color when their associated trap is active. Clicking outside on the activate and deactivate trap buttons is allowed.

Here is a focus trap with some focusable parts.

Here is something.

Here is a another focus trap element. See how it works.

Here is the last trap area.

View demo source

Negative tabindex

This trap has an element with a negative tabindex in the middle, which means that element is focusable but not tabbable. Use the mouse to set focus to it. Once it has focus, you can still use the tab key to go forward or backward in the normal tab order.

View demo source

Negative tabindex last

This trap has an element with a negative tabindex and it's the last element, which means that element is focusable but not tabbable. Use the mouse to set focus to it. Once it has focus, you can still use the tab key to go forward or backward in the normal tab order.

View demo source

Positive tabindex

This trap has 3 buttons which have a positive (greater than 0) tabindex attribute. Per tab order rules, they should get focused first (in 1-2-3 order tabbing forward), then all tabbable nodes without a tabindex attribute (the 3 links, "tabindex 0" and "tabindex ?") should get focused in document position order. The same should happen in reverse when shift+tabbing.

❗️ Positive tabindex support is limited to single-container traps. It is also not 100% accurate to browser behavior in one edge case, which is when tabbing from a negative tabindex node (focusable, not tabbable). In this case, browsers will set focus to the next tabbable node in document position order, regardless of tabindex value (zero or positive). Focus-trap, however, will set focus to the next tabbable node in DOM order. Most of the time, the result will be the same, but there may be slight differences.

⚠️ Using positive tab indexes is not recommended, primarily for accessibility reasons.

⚠️ Tabbing from the last positive tabindex node leading to a zero/default tabindex node will cause a momentary focus escape which focus-trap will identify and rectify to keep tab order working as expected. This momentary escape, however, means some node outside the trap will get focused before focus-trap is able to pull focus back into the trap. If that node is out of view, this may cause the window to scroll to it, not to mention the focus event this outside node will unavoidably receive.

Here is a focus trap with some focusable parts.

View demo source

With open web component

This trap contains an element which is defined in an open web component (i.e. a web component with an open Shadow DOM).

View demo source

Global trap stack

Use window to have access to trap stack. This allows to have more than one focus-trap library version in the same page.

Here is a focus trap with some focusable parts.

Active traps:

View demo source

Customized keyboard navigation

This trap uses the isKeyForward() and isKeyBackward() options to enable the use of the j (backward) and k (forward) keys to navigate the trapped elements using the keyboard.

💬 The tab key still works, but not completely, as it's no longer managed by the trap. To make full use of these options, the tab key should be suppressed entirely or handled differently. You might use these options in a dropdown list where you're moving focus between items using the arrow keys while reserving the tab key for moving beyond the dropdown itself.

Here is a focus trap with some focusable parts.

View demo source

works with inert elements

This trap contains an inert button. Browsers that support this new HTML attribute will render it completely non-interactive, and focus-trap will ignore it too.

⚠️ Check the browser compatibility for the browser you're using right now before trying this demo. It will not work properly if your browser doesn't support the inert attribute.

Here is a focus trap with some focusable parts.

It will avoid this inert button:

View demo source

Keeps focus when removing DOM elements

If the currently focused elemented is removed from the DOM, the focus can move to the document body.

focus-trap ensures that focus remains within the trap.

Here is a focus trap with some focusable parts.

This button will be removed when clicking it:

Reload the page to make the button reappear.

View demo source

Return to the repository