Focus Trap¶
Constrains focus within a subtree when active. Used by modals and overlays to prevent focus from escaping to background content.
Usage¶
ui.focusTrap(
{ id: "modal-trap", active: state.modalOpen },
[
ui.text("Are you sure?"),
ui.button({ id: "confirm", label: "Confirm" }),
ui.button({ id: "cancel", label: "Cancel" }),
]
)
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
required | Unique identifier for the trap |
active |
boolean |
required | Whether focus is currently trapped |
initialFocus |
string |
- | ID of element to focus when trap activates |
returnFocusTo |
string |
- | ID of element to focus when trap deactivates |
key |
string |
- | Reconciliation key |
Behavior¶
When active is true:
- Tab/Shift+Tab cycles only through focusable elements inside the trap
- Focus cannot escape to elements outside the trap
- Attempting to Tab past the last element wraps to the first
- Attempting to Shift+Tab before the first element wraps to the last
When active becomes false:
- Focus is restored to
returnFocusToif specified - Normal Tab navigation resumes
Initial Focus¶
Specify which element receives focus when the trap activates:
ui.focusTrap({
id: "confirm-dialog",
active: state.showConfirm,
initialFocus: "cancel", // Focus "Cancel" by default
}, [
ui.text("Delete this item?"),
ui.button({ id: "delete", label: "Delete" }),
ui.button({ id: "cancel", label: "Cancel" }),
])
Focus Restoration¶
Restore focus to a specific element when the trap closes:
ui.focusTrap({
id: "settings",
active: state.showSettings,
returnFocusTo: "settings-btn", // Return to the button that opened it
}, [...])
Modal Example¶
Focus traps are typically used with modals:
state.showModal && ui.layer({
id: "modal-layer",
backdrop: "dim",
content: ui.focusTrap({
id: "modal-trap",
active: true,
initialFocus: "ok",
returnFocusTo: "open-modal-btn",
}, [
ui.box({ title: "Settings", p: 2 }, [
// Modal content
ui.row({ gap: 2 }, [
ui.button({ id: "ok", label: "OK" }),
ui.button({ id: "cancel", label: "Cancel" }),
]),
]),
]),
})
Nested Traps¶
When traps are nested, only the innermost active trap is effective:
ui.focusTrap({ id: "outer", active: true }, [
// Outer content
ui.focusTrap({ id: "inner", active: state.showInner }, [
// Inner content - focus trapped here when showInner is true
]),
])
Related¶
- Focus Zone - Group focusable widgets
- Modal - Modal dialog widget
- Layer - Generic overlay layer