// live demo
Open a modal and press Tab — focus stays trapped inside. Press Esc or click Close to return focus to the trigger. The live focus log below tracks where focus is at all times. Each button shows off a different v1.1 feature:
Open Modal focuses the first field ·
focus Email jumps straight to the email input (initialFocus) ·
empty dialog has no focusable children, so focus falls back to the dialog itself (fallbackFocus).
// usage
import createFocusTrap from 'focus-trap-tiny'; const modal = document.getElementById('my-modal'); const trap = createFocusTrap(modal, { initialFocus: '#email', // selector, element, fn, or true/false returnFocus: triggerBtn, // where focus goes on close fallbackFocus: modal, // used when nothing is focusable onEscape: () => closeModal(), }); // When modal opens trap.activate(); // When modal closes trap.deactivate(); // If DOM changes dynamically trap.update();
// features
Tab & Shift+Tab
Full bidirectional keyboard cycling through all focusable elements.
Configurable focus
Target initial & return focus by selector, element, or function — restores the trigger by default.
Escape guard
Catches focus that slips out via mouse click or programmatic focus(), not just Tab.
Fallback focus
Empty dialog? Focus falls back to the container so it's never lost outside the trap.
Inert-aware
Skips elements inside [inert] containers and hidden elements.
Dynamic content
Call trap.update() after DOM changes to re-scan focusable elements.
Escape callback
Optional onEscape hook to wire up your close logic.
Tree-shakeable
Pure ESM with zero side-effects. Only ships what you import.