fzf-for-js
A TypeScript port of the FZF command-line fuzzy finder's scoring algorithm for use in the browser.
Repository Health
Technical Analysis
fzf brings the exact fuzzy-matching algorithm behind the popular command-line tool FZF into JavaScript and TypeScript. Instead of reinventing a scoring heuristic, it ports FZF’s Go source line-for-line (tracked against a specific upstream commit hash, with edge cases cross-checked against telescope-fzf-native’s C implementation), so results feel identical to what developers already expect from the CLI tool — bonus points for word boundaries, camelCase transitions, and consecutive character runs.
It ships as a zero-dependency library with both synchronous (Fzf) and asynchronous, cancellable (AsyncFzf) finders, an extended multi-term query syntax, custom item selectors for searching non-string data, and pluggable tiebreakers for stable sort ordering. It’s built for exactly the kind of UI that made FZF famous on the terminal: command palettes, quick-open dialogs, and filterable lists in web apps.
What You Get
- A faithful port of FZF’s v1 and v2 scoring algorithms, ported directly from the upstream Go source and pinned to a specific commit hash
- Both a synchronous
Fzffinder and a cancellable, chunkedAsyncFzffinder for large lists that shouldn’t block the main thread - An extended query syntax (exact-match, prefix, suffix, negation terms) via
extendedMatch/asyncExtendedMatch, in addition to the default basic fuzzy match - A
selectoroption to fuzzy-search over arbitrary objects, not just plain strings, plus pluggable tiebreakers (byLengthAsc,byStartAsc) for deterministic ordering on tied scores - Zero runtime dependencies and dual ESM/UMD builds with full TypeScript type definitions
Common Use Cases
- Building a command palette or quick-open dialog (VS Code / Sublime Text style) inside a web app
- Adding fuzzy filtering to an autocomplete input or searchable dropdown list
- Ranking search-as-you-type results over a dataset already loaded client-side
- Fuzzy-matching file paths, menu items, or any list of structured objects via a custom selector
Under The Hood
Architecture
The library is organized into clearly separated modules under src/lib: runes.ts handles Unicode-correct codepoint indexing, normalize.ts strips diacritics, algo.ts implements the core fuzzyMatchV1/fuzzyMatchV2 scoring functions ported directly from junegunn/fzf’s Go source (the file’s header comment pins the exact upstream commit hashes it was ported from and later updated against), pattern.ts/extended.ts implement the space-separated extended query syntax, matchers.ts composes algo.ts output into basicMatch/extendedMatch/asyncBasicMatch/asyncExtendedMatch, finders.ts defines the BaseFinder/SyncFinder/AsyncFinder classes that own option defaults and post-processing (sort, limit, tiebreakers), and main.ts exposes thin public Fzf/AsyncFzf wrapper classes. Data flows from a one-time rune precomputation per list item at construction time through a per-query match pass; the async finder chunks work in batches of 1000 items via setTimeout/setImmediate and tracks a cancellation token so a stale in-flight search can’t clobber a newer one — the one clear architectural addition beyond a straight algorithm port. Because scoring values flow directly into sort order, any change to the core algorithm functions has ripple effects through matchers, finders, and tiebreakers alike.
Tech Stack
Pure TypeScript compiled with tsc plus Vite, targeting ESNext with dual build outputs (an ESM build and a legacy UMD/CommonJS build via a separate vite-legacy.config.ts), and a standalone type-declarations build step. There are zero runtime dependencies — everything in package.json’s dependency list is a devDependency. The documentation site living alongside the library in src/docs is a separate Vite + React + MDX application (react-router, Tailwind, prism-react-renderer for code highlighting) deployed to Netlify. Tests run under Jest via ts-jest, with coverage uploaded to coveralls.io from GitHub Actions CI (currently pinned to Node 16).
Code Quality
Four dedicated test files under src/lib/__tests__ (algo, main, pattern, tiebreakers) total roughly 960 lines against the library’s own ~2,240 lines — a substantial ratio of test code to implementation for a scoring algorithm where subtle regressions are easy to introduce silently. tsconfig.json enables strict: true, and the public options surface in types.ts is documented field-by-field with TSDoc comments and usage examples. Prettier enforces consistent formatting via a format script; no ESLint configuration is present, so quality leans on strict TypeScript and the test suite rather than a linter.
What Makes It Unique
Most JavaScript fuzzy-search libraries invent their own scoring heuristic. fzf instead does a deliberate, commit-hash-tracked port of the actual FZF Go implementation, cross-referencing edge cases against the telescope-fzf-native C port along the way, so its ranking (word-boundary bonuses, camelCase-transition bonuses, consecutive-match bonuses) matches what terminal FZF users already expect rather than approximating it. The chunked, cancellable async finder for large in-browser lists is a reasonable but incremental addition on top of that core fidelity.
Used by 5 apps in this directory
Actual
Invoicing Finance
Local-first personal finance with envelope budgeting, end-to-end encryption, and multi-device sync — no subscription required.
Cline
AI Code Assistants
An open-source AI coding agent that lives in your editor and terminal — reads and edits your codebase, runs commands, browses the web, and requires human approval for every action by default.
Continue
Developer Tools · AI Development · AI Code Assistants
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.
fountain-ink
Blogging
A self-hostable, decentralized blogging platform built on Lens Protocol — own your content, audience, and distribution forever.
Jan
AI Assistants
Run LLMs 100% locally with full privacy, or connect to cloud AI — your machine, your data, your control.