fzf-for-js

A TypeScript port of the FZF command-line fuzzy finder's scoring algorithm for use in the browser.

Library
npm
v0.5.2
954stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance20
Community36
Maturity56
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture78
Code Quality74
Innovation60
Learning Curve75

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 Fzf finder and a cancellable, chunked AsyncFzf finder 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 selector option 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.

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