Solid Primitives (Active Element)

Reactive document.activeElement tracking and focus-state signals for SolidJS.

Library
npm
v2.1.6
1,554stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
90/100Excellent
Development Activity92
Maintenance100
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
82/100Excellent
Architecture80
Code Quality88
Innovation78
Learning Curve80

@solid-primitives/active-element gives SolidJS applications a reactive read on browser focus state without hand-wiring focus and blur listeners. It exposes a global reactive accessor for document.activeElement, a per-element focus signal, and a use:focus directive for JSX-first ergonomics, so components can react to focus changes the same way they react to any other Solid signal.

Part of the Solid Primitives monorepo — a curated collection of high-quality, community-maintained building blocks for Solid — it follows the project’s shared conventions for SSR safety, tree-shakeable exports, and thorough test coverage, including dedicated SSR tests that assert every primitive degrades to safe no-ops on the server.

What You Get

  • createActiveElement - a reactive Accessor<Element | null> mirroring document.activeElement, updated via capturing focus/blur listeners on window.
  • createFocusSignal - a boolean signal for one element’s focus state, accepting either a raw element or a reactive accessor so it re-subscribes when the target changes.
  • focus directive - a use:focus JSX directive that reports an element’s active state via callback, avoiding manual signal wiring in components.
  • Non-reactive listener helpers - makeActiveElementListener and makeFocusListener for cases where you want the raw event callback instead of a Solid signal.
  • SSR-safe no-ops - every primitive checks isServer and returns inert defaults (null, false, no-op cleanup) so server rendering never throws.

Common Use Cases

  • Custom focus-ring styling - drive component-level focus rings from createFocusSignal instead of relying on :focus-visible alone.
  • Focus-aware analytics - use createActiveElement to log which UI region has focus for accessibility or usage instrumentation.
  • Keyboard navigation components - build comboboxes, menus, and command palettes that need to know which item currently holds focus.
  • Editor/canvas UIs - track whether a text input or contenteditable region is focused to conditionally show toolbars or overlays.

Under The Hood

Architecture The package is a thin, single-file primitive (src/index.ts) built on two shared primitives from the same monorepo — @solid-primitives/event-listener for capturing focus/blur listeners and @solid-primitives/utils for createHydratableSignal and shared directive/MaybeAccessor types — with all four exports (createActiveElement, createFocusSignal, makeActiveElementListener, makeFocusListener) plus a use:focus directive implemented as plain functions guarded by an early isServer branch. There is no internal state machine or class, just closures composed over window/element listeners; the abstraction the package leans on most heavily is the capturing-listener contract of makeEventListener from event-listener, so a change there would ripple through every export here.

Tech Stack TypeScript across a pnpm workspace of roughly 85 sibling primitive packages, built with Node’s experimental type-stripping via a custom loader (@nothing-but/node-resolve-ts) rather than tsc/tsup directly, tested with Vitest in both client and SSR modes from a shared configs/vitest.config.ts, linted with a flat ESLint config plus Prettier, versioned and published via Changesets, and shipped through GitHub Actions workflows that cover tests, formatting, CodeQL scanning, and dual npm/JSR releases. The package declares solid-js ^1.6.12 as a peer dependency.

Code Quality Two dedicated test files exercise the whole public surface: an index.test.ts that dispatches real FocusEvents inside createRoot to assert reactive behavior and cleanup, and a server.test.ts that explicitly asserts every primitive is a safe no-op under SSR. Source code is fully typed with no use of any, exported functions carry JSDoc with usage examples and doc links, and the monorepo enforces a zero-warnings ESLint policy plus CI-checked formatting.

API Design The API mirrors Solid’s own create*/make* naming conventions, offering three levels of abstraction for the same capability — a raw callback listener, a reactive signal, and a JSX directive — so consumers can pick the ergonomics level that fits their component. Focus tracking itself isn’t a novel concept, but the consistent multi-level API and inline documented examples make it easy to drop into an existing Solid codebase with minimal boilerplate.

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