focus-trap

A tiny vanilla-JS library that traps keyboard focus inside a DOM node for accessible modals and dialogs

Library
npm
v8.2.2
1,563stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
84/100Excellent
Development Activity96
Maintenance84
Community56
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture78
Code Quality82
Innovation68
Learning Curve80

focus-trap is a small, dependency-light JavaScript module that constrains Tab and Shift+Tab navigation to a set of DOM containers, preventing keyboard users from tabbing out of a modal, drawer, or menu while it is open. It builds on tabbable to compute the current set of focusable elements, restores focus to the previously focused element on deactivation, and exposes a rich lifecycle-hook API (onActivate, onPostActivate, onDeactivate, onPostDeactivate, pause/unpause) so higher-level component libraries can wire it into their own animation and rendering cycles.

Because it operates purely on the DOM rather than any particular UI framework, focus-trap is typically consumed through a thin wrapper such as focus-trap-react rather than being called directly, though it works perfectly well framework-free. It is one of the most widely depended-upon building blocks for meeting WCAG 2.1 keyboard-trap and modal-dialog accessibility criteria in the JavaScript ecosystem.

What You Get

  • createFocusTrap(element, options) factory that wraps one or more DOM containers into a single trap
  • Automatic tab-order detection via the tabbable library, including Shadow DOM support
  • Configurable initialFocus, fallbackFocus, and setReturnFocus targets for precise focus control
  • A full lifecycle-hook API (onActivate/onPostActivate/onDeactivate/onPostDeactivate/onPause/onUnpause) for coordinating with modal animations
  • pause()/unpause() support for nesting multiple focus traps (e.g. a confirm dialog inside a modal)
  • TypeScript type definitions and both ESM/CJS/UMD builds

Common Use Cases

  • Trapping focus inside an accessible modal or dialog while it is open
  • Containing focus within a slide-out drawer, off-canvas menu, or command palette
  • Building framework-specific wrappers (React, Vue, Svelte) around a single vanilla-JS focus implementation
  • Coordinating focus handoff between nested overlays such as a confirmation prompt opened from within a modal

Under The Hood

Architecture - The core lives in a single index.js module exporting createFocusTrap(elements, options). Internally it normalizes the elements argument into an array of “trap containers”, tracks the currently active container set in a closure-scoped state object, and attaches document-level focusin, keydown, click, and pointerdown listeners that redirect focus back inside the trap whenever it would otherwise escape. Activation/deactivation is modeled as an explicit state machine (activate/deactivate/pause/unpause) so nested traps can suspend one another cleanly.

Tech Stack - Written in plain ES2017+ JavaScript with a single runtime dependency, tabbable, used to compute the DOM’s current tab order (including Shadow DOM roots). The project builds ESM, CJS, and UMD bundles via Rollup/Babel, ships hand-written index.d.ts TypeScript declarations rather than generated ones, and has zero DOM-framework dependency, which is what lets it work identically in React, Vue, Svelte, or framework-free code.

Code Quality - The test/suites directory contains an extensive Jest + jsdom unit-test suite plus a Cypress end-to-end suite (test:e2e) that exercises real browser tab/click behavior, and CI runs format/lint/type-check/unit/e2e on every push. Options are validated defensively (e.g. throwing when a trap has no tabbable node and no fallbackFocus), and the lifecycle-hook contract is documented exhaustively in the README and mirrored in the type definitions.

API Design - The public surface is a single factory function returning a trap object with activate(), deactivate(), pause(), and unpause() methods, plus a dozen well-named configuration options (initialFocus, fallbackFocus, escapeDeactivates, clickOutsideDeactivates, allowOutsideClick) that each accept a value, selector string, or function for maximum flexibility. Getting started requires only createFocusTrap(el).activate(), while advanced lifecycle coordination is opt-in via the hook callbacks.

Used by 7 apps in this directory

TypeScript
80%
Other

Directus

CMS · Low Code Platforms

37,462

Connect any SQL database and get instant REST and GraphQL APIs, a visual management Studio, and a native MCP server for AI agents — free for most organizations.

View details
93
Repo Health
82
Technical
78
Dependency
Built with
TypeScript80%
Vue18%
Updated yesterday
Ruby
63%
AGPL 3.0

Forem

Community · Blogging

22,769

Open source Ruby on Rails platform for building developer communities with articles, discussions, and social profiles—the same software that powers dev.to.

View details
84
Repo Health
79
Technical
70
Dependency
Built with
Ruby63%
JavaScript19%
HTML13%
Updated yesterday
Ruby
59%
MIT

OnetimeSecret

Security

2,900

Generate self-destructing single-use links to share passwords and sensitive data without leaving traces in inboxes or chat logs.

View details
91
Repo Health
81
Technical
74
Dependency
Built with
Ruby59%
TypeScript26%
Vue11%
Updated today
Python
37%
Other

Open WebUI

AI Assistants · AI Agents

149,204

The extensible, privacy-first AI platform that runs Ollama, OpenAI, and any LLM backend behind a polished, feature-packed web interface.

View details
91
Repo Health
75
Technical
66
Dependency
Built with
Python37%
Svelte33%
JavaScript22%
Updated today
TypeScript
60%
MIT

Scalar

Developer Tools

15,944

Beautiful, interactive OpenAPI documentation with a built-in offline-first API client and multi-language code generation — all in one open-source platform.

View details
90
Repo Health
89
Technical
66
Dependency
Built with
TypeScript60%
Vue35%
Updated yesterday
Python
58%
Other

Sentry

Security · Developer Tools · Monitoring

44,574

Developer-first error tracking and performance monitoring platform with AI-powered root-cause analysis across 20+ languages and frameworks.

View details
95
Repo Health
80
Technical
70
Dependency
Built with
Python58%
TypeScript41%
Updated today
PHP
45%
AGPL 3.0

solidtime

Productivity · Invoicing Finance

8,860

Modern open-source time tracker for freelancers and agencies with invoicing, multi-org support, and Toggl/Clockify migration built in.

View details
84
Repo Health
81
Technical
70
Dependency
Built with
PHP45%
TypeScript30%
Vue23%
Updated yesterday

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search