Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Constrain keyboard focus within a container. Tab/Shift+Tab cycle inside the boundary, focus auto-moves in on activation, and restores on deactivation.
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.
<section data-focus-trap> <input type="text" autofocus> <button>Save</button> <button>Cancel</button></section>
[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.| 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. |
The trap watches the DOM with a MutationObserver. Adding a data-focus-trap element dynamically activates it immediately. Removing the element restores focus automatically.
<button id="open-btn">Edit</button><div id="panel-target"></div> <script> document.getElementById('open-btn').addEventListener('click', () => { const panel = document.createElement('section'); panel.setAttribute('data-focus-trap', ''); panel.innerHTML = ` <input type="text" autofocus> <button id="close-btn">Close</button> `; document.getElementById('panel-target').appendChild(panel); panel.querySelector('#close-btn').addEventListener('click', () => { panel.remove(); // focus auto-restores to #open-btn }); });</script>
You can also activate and deactivate a trap by adding or removing the attribute on an existing element:
The module exports functions for programmatic control:
import { activateTrap, deactivateTrap } from './utils/focus-trap-init.js'; // Activate on a specific elementactivateTrap(myPanel); // Deactivate and restore focusdeactivateTrap(myPanel);
| 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. |
[autofocus] integration provides immediate keyboard access to the primary input.aria-label or a heading inside the trap to give screen reader context about the trapped region.show() (not showModal()).no-autofocus.<dialog> with showModal() instead — it traps focus natively.