
Mentions is my open-source, framework-agnostic mention system: @users, #tags, and /commands from one ~14KB core with zero dependencies, working across React, Vue, and Svelte, with AI ghost-text completions built in.
“One ~14KB headless core drives mentions in React, Vue, and Svelte. Every alternative I benchmarked was heavier and locked to one framework.”
— Gagan Raj
CONSTRAINTS
- Core budget: stay small enough that nobody thinks twice about adding it
- Zero runtime dependencies, so no supply-chain surface
- One behaviour spec across three frameworks
- WAI-ARIA compliant out of the box
THE BUILD
While building Dataweaver I needed mentions in a chat input: @columns, /commands, the pattern every product eventually grows. Every library I evaluated was welded to one framework, heavy, and unaware that inputs now autocomplete with AI. I wrote my own core and figured other developers were stuck in the same spot.
The design bet was headless-first: a plain TypeScript engine that owns parsing, matching, and selection state, with thin adapters per framework. React, Vue, and Svelte each get an idiomatic wrapper around the same core, so behaviour stays identical and fixes land once. Ghost-text AI completion is a first-class provider interface rather than a bolt-on, because that is how people type now.
DECISIONS — INCLUDING THE REJECTED ONES
Architecture
CHOSE Headless TypeScript core with per-framework adapters
REJECTED A React component ported twice
Ports drift. A single engine with thin adapters keeps three frameworks pixel-identical in behaviour and cuts the maintenance to one surface.
Dependencies
CHOSE Zero
REJECTED Pulling in a positioning or parsing library
A utility library that brings friends stops being a utility. The whole thing fits in ~14KB and audits in one sitting.
AI completions
CHOSE Ghost-text provider interface in the core
REJECTED Leaving AI integration to userland
Suggest-as-you-type is the modern default. Making it a provider keeps the core dependency-free while letting apps plug in any model.
OUTCOME
- ~14KB core, zero dependencies
- Ships for React, Vue, and Svelte from one engine
- WAI-ARIA compliant listbox and combobox semantics
- Extracted from a production need inside Dataweaver
CRAFT LEDGER
- Headless core + adapters
- Ghost-text provider API
- Zero-dependency build
- Framework parity tests