Focus Trap
Constrains Tab/Shift+Tab focus cycling within a container element. Useful for dialogs, sidebars, and any overlay that should capture keyboard focus.
import { createFocusTrap } from 'phoundry-ui'; Interactive Focus Trap
Click to open a focus-trapped panel.
Show code
<script lang="ts">
import { createFocusTrap } from 'phoundry-ui';
import { Button, TextInput } from 'phoundry-ui';
let trapActive = $state(false);
const trap = createFocusTrap({
escapeDeactivates: true,
onEscape: () => (trapActive = false),
});
</script>
<Button onclick={() => (trapActive = true)}>Activate Trap</Button>
{#if trapActive}
<div use:trap.action class="p-4 border rounded-lg space-y-3">
<TextInput placeholder="First input (auto-focused)" />
<TextInput placeholder="Second input" />
<div class="flex gap-2">
<Button variant="primary">Confirm</Button>
<Button onclick={() => (trapActive = false)}>Cancel</Button>
</div>
<p class="text-xs text-txt-tertiary">
Tab cycles within this panel. Press Escape to exit.
</p>
</div>
{/if}FocusTrapOptions
| Prop | Type | Default | Description |
|---|---|---|---|
| autoFocus | boolean | true | Auto-focus the first focusable element when the trap activates. |
| returnFocusOnDeactivate | boolean | true | Return focus to the previously focused element on deactivation. |
| escapeDeactivates | boolean | false | Allow Escape key to deactivate the trap. |
| onEscape | () => void | — | Called when Escape is pressed (if escapeDeactivates is true). |
Return Value
| Prop | Type | Default | Description |
|---|---|---|---|
| action | Action | — | Svelte action: use:trap.action or use:trap.action={{ enabled: boolean }}. When enabled is false, Tab capture is off (e.g. stacked modals not on top) without restoring focus. |
| activate() | () => void | — | Manually activate the trap (called automatically by the action when enabled). |
| deactivate(options?) | { restoreFocus?: boolean } | — | Manually deactivate. Pass restoreFocus: false to pause without moving focus (stacked overlays). Defaults to the trap’s returnFocusOnDeactivate when omitted. |
| active | boolean (readonly) | — | Whether the trap is currently active. |
FocusTrapActionParams (use:trap.action parameter)
| Prop | Type | Default | Description |
|---|---|---|---|
| enabled | boolean | true | When false, the action does not activate Tab capture until set true again (see action update). |
Usage tips
- Used internally by
Modaland the modal manager overlay — you only need this directly for custom dialogs or sidebar panels. - The action activates the trap when applied (if
enabledis not false) and cleans up ondestroy. - Focus returns to the previously focused element when the trap deactivates (unless
returnFocusOnDeactivateis false). - Only visible, non-disabled focusable elements participate in the cycle.
- Set
escapeDeactivates: trueand provide anonEscapecallback to handle closing.