Adding Fuzzy Search to Your Static Website with Fuse.js

by Michael G.

5 min read
Featured image for Adding Fuzzy Search to Your Static Website with Fuse.js

Learn how to add fuzzy search to your static website using Fuse.js. This tutorial will guide you through the process of integrating a search feature that provides relevant results to users.

Adding a search feature to a static website can be challenging but luckily there are some great tools out there that can help. In this article, I will be using Fuse.js, a small fuzzy search library with zero dependecies. On a normal website, you would have a backend server with an API route to handle the search. If you are using a CMS (Content Management System), they ususally have a way to implement search via their API. If you're dataset is small, using a fuzzy search library like Fuse.js is a great option.

For this article, I am going to use React, Tailwind and Typescript but you can use any frontend framework or library you like.

Installation

To get started, you will need to install Fuse.js.

npm install fuse.js

User Interface

Initial search component with static data

Let's build the search component with just some static HTML. The list for now will be a static list.

export default function Search() {
  return (
    <div className="mt-2">
      <input
        name="search"
        type="text"
        placeholder="Search for games"
        className="block w-full rounded-md border-2 p-2 py-1.5 text-sm leading-6 text-slate-900 shadow-sm placeholder:text-slate-400"
      />
      <ul className="mt-4 rounded-md border bg-slate-100 p-4">
        <li className="my-2">Game 1</li>
        <li className="my-2">Game 2</li>
        <li className="my-2">Game 3</li>
      </ul>
    </div>
  )
}

Adding state to the search component

Nice! We have our initial search component with some basic HTML and static data. Now let's add some state to the component to handle the search input.

We need an event to fire when the user types into the input field. I will store what the user types in a state variable called query. Let's make the function handleSearch to handle the input change. Your updated component should look like this:

import { useState } from 'react'

export default function Search() {
  const [query, setQuery] = useState<string>('')

  const handleSearch = (value: string) => {
    setQuery(value)
  }

  return (
    <div className="mt-2">
      <input
        value={query}
        onChange={({ target: { value } }) => handleSearch(value)}
        name="search"
        type="text"
        placeholder="Search for games"
        className="block w-full rounded-md border-2 p-2 py-1.5 text-sm leading-6 text-slate-900 shadow-sm placeholder:text-slate-400"
      />

      <ul className="mt-4 rounded-md border bg-slate-100 p-4">
        <li className="my-2">Game 1</li>
        <li className="my-2">Game 2</li>
        <li className="my-2">Game 3</li>
      </ul>
    </div>
  )
}

Adding Fuse.js to the search component

Now that we have our search component working with state, let's add Fuse.js to our component. I will use Fuse.js to search through the list of games and filter the results based on the user's input. The final component should look like this:

import { useState } from 'react'
import Fuse, { type FuseResult } from 'fuse.js'

type Game = {
  title: string
  system: string
  genre: string
}

const games = [
  {
    title: 'The Legend of Zelda: Breath of the Wild',
    system: 'Nintendo Switch',
    genre: 'Action-adventure'
  },
  {
    title: 'Super Mario Odyssey',
    system: 'Nintendo Switch',
    genre: 'Platformer'
  },
  {
    title: 'Halo Infinite',
    system: 'Xbox Series X',
    genre: 'First-person shooter'
  },
  {
    title: 'God of War',
    system: 'PlayStation 4',
    genre: 'Action-adventure'
  },
  {
    title: 'The Last of Us Part II',
    system: 'PlayStation 4',
    genre: 'Action-adventure'
  }
] as Game[]

export default function Search() {
  const [query, setQuery] = useState<string>('')
  const [results, setResults] = useState<FuseResult<Game>[]>([])

  const handleSearch = (value: string) => {
    const fuse = new Fuse(games, {
      keys: ['title', 'system'],
      includeScore: true,
      isCaseSensitive: false,
      includeMatches: true,
      threshold: 0.5,
      minMatchCharLength: 2
    })
    const searchResult = fuse.search(query)

    setResults(searchResult)
    setQuery(value)
  }

  return (
    <div className="mt-2">
      <input
        onChange={({ target: { value } }) => handleSearch(value)}
        name="search"
        type="text"
        placeholder="Search for games"
        className="block w-full rounded-md border-2 p-2 py-1.5 text-sm leading-6 text-slate-900 shadow-sm placeholder:text-slate-400"
      />

      {results.length > 0 && (
        <ul className="mt-4 rounded-md border bg-slate-100 p-4">
          {results.map((result) => (
            <li key={result.item.title} className="my-2">
              {result.item.title}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

We added an array of games that will work as our dataset as a simple example. We then created a new instance of Fuse inside the search function with some options.

Here are what each option does here:

  • keys: The keys to search in the dataset. We are searching in the title and system keys.
  • includeScore: Whether to include the score in the result
  • isCaseSensitive: Whether the search is case sensitive
  • includeMatches: Whether to include matches in the result
  • threshold: The threshold to consider a match. 0.0 is perfect match and 1.0 is match anything
  • minMatchCharLength: The minimum number of characters to match

The list was updated to show the results of the search. If there are no results, the list will not be shown. The search function was also updated to call the search method from Fuse. You might have to adjust the Fuse.js options to fit your needs.

Conclusion

That's it! You now have a fuzzy search feature on your static website using Fuse.js. You can now search through the list of games and filter the results based on the user's input. Remember that this is only suitable for smaller datasets, always use an API if you are working with large datasets. Feel free to customize the search component to fit your needs.

Resources

Fuse.js


Michael G.

Michael G.

Michael, together with his wife, own Space City Web Designs. He is a software engineer with years of experience working at companies of various sizes. In his spare time, he likes to code, play video games and travel.

Read all articles by Michael G.

What Our Clients Said

“Mary with Space City Web Designs is amazing! Her communication is outstanding and she makes sure you love everything about your website. If there is anything you don't like, they will fix it immediately! The website is everything I have thought of. Working with Mary was great and I highly recommend Space City Web Designs.”

Whitney Evans avatar
Whitney Evans
Owner of Paw Balm by KW Walkers

“Space City Web Designs was easy to work with. My finished website looked very professional. I am very happy with the end result.”

Jessica Will avatar
Jessica Will
Owner of CW Enterprises
guy on computer with rocket launch in background

Let's start your journey with us

Ready to start your project?

We can make your brand look online without breaking the bank. Your website is the first impression you make on your customers. Make it count.