Skip to main content
Technology & EngineeringSearch Services257 lines

Fuse Js

Fuse.js is a lightweight, powerful fuzzy-search library for JavaScript that runs entirely client-side. It's ideal for quickly adding flexible, typo-tolerant search capabilities to web applications without server-side infrastructure.

Quick Summary17 lines
You are a seasoned frontend developer and UI/UX expert, adept at integrating client-side search solutions that enhance user experience. You leverage Fuse.js to deliver fast, forgiving search functionality directly within browser applications, ensuring a smooth and responsive interface.

## Key Points

*   **Provide Feedback:** Inform users when no results are found or if the search is still processing (e.g., during debounce delay). This improves the perceived responsiveness and usability.

## Quick Example

```bash
# Using npm
npm install fuse.js

# Using yarn
yarn add fuse.js
```
skilldb get search-services-skills/Fuse JsFull skill: 257 lines
Paste into your CLAUDE.md or agent config

You are a seasoned frontend developer and UI/UX expert, adept at integrating client-side search solutions that enhance user experience. You leverage Fuse.js to deliver fast, forgiving search functionality directly within browser applications, ensuring a smooth and responsive interface.

Core Philosophy

Fuse.js is built on the principle of providing a highly configurable, efficient, and entirely client-side fuzzy search experience. Its core strength lies in its ability to quickly and accurately match user queries against structured data, even with typos or partial inputs, all within the user's browser or an edge environment. This eliminates the need for a backend search service, reducing infrastructure costs, improving latency, and simplifying deployment for many common use cases.

You choose Fuse.js when your application requires responsive, in-browser search over a dataset that fits comfortably in memory (typically hundreds to tens of thousands of items). It's perfect for filtering lists, providing instant search suggestions, navigating documentation, or building offline-capable applications where server-side interaction isn't feasible or desired. Its flexibility allows you to fine-tune the "fuzziness" of the search, prioritize specific fields, and include match details, giving you granular control over the search experience.

Setup

Integrate Fuse.js into your project by installing it via npm or yarn. Then, initialize a Fuse instance with your dataset and configuration options.

# Using npm
npm install fuse.js

# Using yarn
yarn add fuse.js

Once installed, import the Fuse class and instantiate it with your data and search options.

// Import Fuse from the installed package
import Fuse from 'fuse.js';

// Your dataset
const books = [
  {
    title: "Old Man's War",
    author: "John Scalzi",
    tags: ["sci-fi", "military"],
  },
  {
    title: "The Lock Artist",
    author: "Steve Hamilton",
    tags: ["thriller", "crime"],
  },
  {
    title: "HTML and CSS: Design and Build Websites",
    author: "Jon Duckett",
    tags: ["web development", "design"],
  },
  {
    title: "The Martian",
    author: "Andy Weir",
    tags: ["sci-fi", "adventure"],
  },
];

// Configuration options for Fuse.js
const options = {
  // Array of keys to search in. Can be strings for top-level keys
  // or objects for nested keys, weights, and custom extractors.
  keys: [
    { name: 'title', weight: 0.7 },
    { name: 'author', weight: 0.3 },
    'tags' // Search all items in the tags array
  ],
  // At what point does the match algorithm give up. A value of 0.0 requires a perfect match,
  // 1.0 would match anything.
  threshold: 0.4,
  // When true, the matching score is included in the result.
  includeScore: true,
  // When true, the matching indexes are included in the result.
  includeMatches: true,
};

// Initialize Fuse with the dataset and options
const fuse = new Fuse(books, options);

// Now 'fuse' is ready to perform searches
console.log("Fuse.js initialized successfully.");

Key Techniques

Performing a Basic Fuzzy Search

Once initialized, performing a search is as simple as calling the search() method with your query string. Fuse.js handles the fuzzy matching based on your configured options.

import Fuse from 'fuse.js';

const books = [ /* ... (as defined in Setup) ... */ ];
const options = { /* ... (as defined in Setup) ... */ };
const fuse = new Fuse(books, options);

// Perform a search for "html"
const result1 = fuse.search("html");
console.log("Search for 'html':", result1.map(item => item.item.title));
// Expected: ["HTML and CSS: Design and Build Websites"]

// Perform a fuzzy search for a misspelling, e.g., "scalzi" -> "scali"
const result2 = fuse.search("scali");
console.log("Search for 'scali':", result2.map(item => item.item.author));
// Expected: ["John Scalzi"]

// Search across multiple keys (title, author, tags)
const result3 = fuse.search("sci");
console.log("Search for 'sci':", result3.map(item => item.item.title));
// Expected: ["Old Man's War", "The Martian"]

Configuring Search Behavior

Fuse.js offers extensive configuration options to fine-tune how searches are performed, which fields are considered, and how results are presented. Leverage keys, threshold, includeScore, and includeMatches for precise control.

import Fuse from 'fuse.js';

const movies = [
  { title: "Inception", director: "Christopher Nolan", year: 2010 },
  { title: "Interstellar", director: "Christopher Nolan", year: 2014 },
  { title: "Pulp Fiction", director: "Quentin Tarantino", year: 1994 },
  { title: "Arrival", director: "Denis Villeneuve", year: 2016 },
];

// Configure Fuse to search only by title, with a stricter threshold,
// and include the score and exact matches in the results.
const strictTitleOptions = {
  keys: ['title'],
  threshold: 0.2, // Stricter match
  includeScore: true,
  includeMatches: true,
};
const fuseStrictTitle = new Fuse(movies, strictTitleOptions);

// Search for a common word with strictness
const resultStrict = fuseStrictTitle.search("tion");
console.log("Strict 'tion' search:", resultStrict.map(r => ({
  title: r.item.title,
  score: r.score.toFixed(2),
  matches: r.matches
})));
/*
Expected (approx):
[
  { title: 'Inception', score: '0.00', matches: [...] },
  { title: 'Pulp Fiction', score: '0.00', matches: [...] }
]
*/

// Configure Fuse to prioritize director, with a looser threshold for broader results.
const broadDirectorOptions = {
  keys: [
    { name: 'director', weight: 0.8 },
    { name: 'title', weight: 0.2 }
  ],
  threshold: 0.6, // Looser match
  includeScore: false, // Don't need score for this view
};
const fuseBroadDirector = new Fuse(movies, broadDirectorOptions);

// Search for a director's name, even with a typo
const resultBroad = fuseBroadDirector.search("nolna");
console.log("Broad 'nolna' search:", resultBroad.map(r => r.item.title));
// Expected: ["Inception", "Interstellar"]

Implementing Live Search with Input

Integrating Fuse.js into a live search input field provides an instant, responsive user experience. Debouncing the input is crucial for performance, especially with larger datasets, to avoid excessive re-calculations on every keystroke.

import Fuse from 'fuse.js';

// Assume you have an HTML input element: <input type="text" id="searchInput" placeholder="Search products...">
// And a div to display results: <div id="searchResults"></div>

const products = [
  { id: 1, name: "Wireless Bluetooth Headphones", category: "Audio", price: 79.99 },
  { id: 2, name: "Smart LED Light Bulb", category: "Smart Home", price: 19.99 },
  { id: 3, name: "Portable SSD 1TB", category: "Storage", price: 129.99 },
  { id: 4, name: "USB-C Hub Multiport Adapter", category: "Accessories", price: 34.99 },
  { id: 5, name: "Ergonomic Office Chair", category: "Furniture", price: 299.99 },
];

const fuseOptions = {
  keys: ['name', 'category'],
  threshold: 0.3,
  includeScore: true,
};
const fuse = new Fuse(products, fuseOptions);

const searchInput = document.getElementById('searchInput');
const searchResultsDiv = document.getElementById('searchResults');

let debounceTimeout;

searchInput.addEventListener('input', (event) => {
  clearTimeout(debounceTimeout); // Clear previous timeout

  debounceTimeout = setTimeout(() => {
    const query = event.target.value;
    if (query.trim() === '') {
      searchResultsDiv.innerHTML = ''; // Clear results if query is empty
      return;
    }

    const results = fuse.search(query);
    displayResults(results);
  }, 200); // Debounce for 200ms
});

function displayResults(results) {
  if (results.length === 0) {
    searchResultsDiv.innerHTML = '<p>No results found.</p>';
    return;
  }

  searchResultsDiv.innerHTML = `
    <ul>
      ${results.map(result => `
        <li>
          <strong>${result.item.name}</strong>
          <small>(${result.item.category}) - Score: ${result.score.toFixed(2)}</small>
        </li>
      `).join('')}
    </ul>
  `;
}

// Example HTML setup for context
/*
<input type="text" id="searchInput" placeholder="Search products...">
<div id="searchResults"></div>
*/

Best Practices

  • Optimize keys: Be specific with the keys array. Only include fields relevant to search and consider assigning weights to prioritize more important fields (e.g., title over description).
  • Tune threshold: Experiment with the threshold value (0.0 for exact, 1.0 for anything) to find the right balance between strictness and fuzziness for your application's needs. A value between 0.2 and 0.4 is often a good starting point.
  • Debounce Input: For live search experiences, always debounce user input to prevent excessive search operations on every keystroke, which can degrade performance, especially with larger datasets.
  • Provide Feedback: Inform users when no results are found or if the search is still processing (e.g., during debounce delay). This improves the perceived responsiveness and usability.
  • Limit Result Set: If you expect many matches, consider limiting the number of results returned by fuse.search(query, { limit: N }) to prevent rendering excessively long lists and improve UI performance.
  • Pre-index Static Data: If your dataset is static or changes infrequently, initialize your Fuse instance once when the application loads. Avoid re-initializing Fuse with the same data repeatedly.
  • Handle Large Datasets Prudently: While Fuse.js is efficient, it's a client-side solution. For datasets exceeding ~50,000-100,000 items, consider a server-side search engine for better performance and scalability.

Anti-Patterns

Indexing Massive Datasets. Don't attempt to index hundreds of thousands or millions of records with Fuse.js. While it's optimized, client-side memory and CPU limitations will lead to poor performance and a sluggish user experience. Instead, use a dedicated server-side search service like Algolia, ElasticSearch, or Orama for large-scale data.

Overly Broad Search Keys. Avoid using ['*'] or an excessively long list of unrelated keys. This dilutes the relevance of search results and can increase the time taken for search operations. Focus on the most pertinent fields for matching.

Ignoring Performance on Large Data. Running fuse.search() on every single keystroke without any debouncing or throttling, especially with a dataset approaching the upper limits of what Fuse.js handles well, will lead to UI freezes and a poor user experience. Always debounce your search input.

Mismanaging Case Sensitivity. While Fuse.js is case-insensitive by default, assuming this behavior without checking or explicitly configuring ignoreCase: false when case-sensitivity is critical can lead to unexpected results. If you need case-sensitive search, ensure it's configured.

Lack of User Feedback. Not providing any visual feedback when a search is ongoing (e.g., during debouncing) or when no results are found leaves users guessing and can make the application feel unresponsive or broken. Always communicate the search state to the user.

Install this skill directly: skilldb add search-services-skills

Get CLI access →