fzf for JavaScript

repository·dev·Indexed 21 days ago

https://github.com/ajitid/fzf-for-js

A JavaScript port of the FZF fuzzy finding algorithm for high-quality fuzzy searching in browser contexts and web applications. It provides the Fzf class for synchronous searches and AsyncFzf for non-blocking searches on large lists. Features include customizable tiebreakers, case sensitivity options, diacritic normalization, and support for non-string lists via selector functions. Version 0.5.2.

Tokens
6.7K
Snippets
30
Records
40
Agent score
76%

What's inside fzf

  1. Install FZF via npm or Deno

    dev

    Node.js

    Install the package using npm:

    npm i fzf

    Deno

    Import FZF directly from an ESM provider:

    // Use the latest version
    import { Fzf } from "https://esm.sh/fzf";
    
    // Pin to a specific version
    import { Fzf } from "https://esm.sh/fzf@0.5.1";
    
    // Use an alternative source
    import { Fzf } from "https://cdn.skypack.dev/fzf?dts";
  2. Basic usage of the Fzf class

    dev

    To use FZF, import the Fzf class, instantiate it with a list of items, and use the .find() method to perform a fuzzy search. The .find() method returns an array of entries, where each entry contains the original item and its ranking information.

    import { Fzf } from 'fzf'
    
    const list = ['go', 'javascript', 'python', 'rust', 
                  'swift', 'kotlin', 'elixir', 'java', 
                  'lisp', 'v', 'zig', 'nim', 'rescript', 
                  'd', 'haskell']
    
    const fzf = new Fzf(list)
    const entries = fzf.find('li')
    console.log('ranking is:')
    entries.forEach(entry => console.log(entry.item)) // lisp kotlin elixir
  3. Migrate from v0.4 to v0.5

    dev

    The primary change in v0.5 concerns the tiebreakers option. If you are not using custom tiebreakers, a simple version bump is sufficient. If you use custom tiebreakers, note that the third argument of the tiebreaker function has changed from options to selector.

    // Before v0.5
    function byTrimmedLengthAsc(a, b, options) {
      return options.selector(a.item).trim().length - options.selector(b.item).trim().length;
    }
    
    // v0.5 and later
    function byTrimmedLengthAsc(a, b, selector) {
      return selector(a.item).trim().length - selector(b.item).trim().length;
    }
    
    const fzf = new Fzf(list, {
      tiebreakers: [byTrimmedLengthAsc]
    });
  4. Migrate from v0.3 to v0.4: Use `options.forward` for match priority

    dev

    The forward option was introduced in v0.4. It determines whether the first match from the start of the string is highlighted. By default, it is enabled. To maintain the v0.3 behavior (where matches appearing later in the string might be prioritized/highlighted), set forward: false.

    const fzf = new Fzf(list, {
      forward: false,
      // ... other options
    });
  5. Migrate from v0.3 to v0.4: Configure `options.normalize`

    dev

    In v0.4, normalize is enabled by default, which removes diacritics/accents (e.g., 'fe' will match 'Caffè'). If you want to disable this behavior and match exact characters, set normalize: false.

    const fzf = new Fzf(list, {
      normalize: false,
      // ... other options
    });
  6. Highlight matched characters in UI

    dev

    Each entry returned by fzf.find() includes a positions property (a Set of indices) representing the characters that matched the query. You can use these indices to apply styling (like <b> tags in React) to the matched parts of the string.

    Note: When using a selector, ensure you call .normalize() on the string used for highlighting to get correct indices.

    // Example using React to highlight indices
    const HighlightChars = (props) => {
      const chars = props.str.split("");
      const nodes = chars.map((char, i) => {
        if (props.indices.has(i)) {
          return <b key={i}>{char}</b>;
        } else {
          return char;
        }
      });
      return <>{nodes}</>;
    };
    
    // Usage with an entry from fzf.find()
    const reactElement = <HighlightChars
      str={entry.item.normalize()}
      indices={entry.positions}
    />;
  7. Use tiebreakers to resolve score ties

    dev

    A Tiebreaker is a function used to sort result entries when their fuzzy scores are identical. It behaves like a JavaScript Array.sort compare function but receives a third argument: the selector function. Tiebreakers are evaluated from left to right in the tiebreakers array until a tie is broken.

    FZF includes built-in tiebreakers:

    • byLengthAsc (sort by length ascending)
    • byStartAsc (sort by starting position ascending)

    Note: Tiebreakers only function if sort is set to true.

    function byLengthAsc(a, b, selector) {
      return selector(a.item).length - selector(b.item).length;
    }
    
    const fzf = new Fzf(list, { tiebreakers: [byLengthAsc] });