webdevpuneet.com

Fuse.js Typo-Tolerant Product Search — HTML CSS JS Demo

Fuse.js Typo-Tolerant Product Search with Threshold Tuning · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

Requires
<div class="fp-wrap">
  <header class="fp-hero">
    <span class="fp-eyebrow">Fuzzy search · Fuse.js</span>
    <h2 class="fp-title">Find it, even with typos</h2>
  </header>

  <div class="fp-search">
    <svg class="fp-ico" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.5" y2="16.5"/></svg>
    <input id="fpQ" type="search" placeholder="Search products, brands, tags…" autocomplete="off" spellcheck="false" aria-label="Search products">
    <button id="fpClear" class="fp-clear" type="button" aria-label="Clear search" hidden>×</button>
    <kbd class="fp-kbd" aria-hidden="true">/</kbd>
  </div>
  <p class="fp-dym" id="fpDym" aria-live="polite"></p>

  <div class="fp-panel">
    <div class="fp-try"><span class="fp-lbl">Try a typo</span>
      <button type="button">hedphones</button>
      <button type="button">sneekers</button>
      <button type="button">blutooth speeker</button>
      <button type="button">mecanical keybord</button>
    </div>
    <div class="fp-tune">
      <div class="fp-tune-top">
        <label class="fp-lbl" for="fpThr">Strictness</label>
        <span class="fp-hint" id="fpThrHint"></span>
        <b id="fpThrVal">0.30</b>
      </div>
      <input id="fpThr" type="range" min="0" max="0.8" step="0.05" value="0.3" aria-describedby="fpThrHint">
      <div class="fp-scale" aria-hidden="true"><span>Exact</span><span>Forgiving</span><span>Noisy</span></div>
    </div>
  </div>

  <div class="fp-cats" id="fpCats" role="group" aria-label="Filter by category"></div>
  <p class="fp-count" id="fpCount" aria-live="polite"></p>
  <ul class="fp-grid" id="fpGrid"></ul>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Typo tolerance
Typos, abbreviations and dropped letters are handled by Fuse.js Bitap matching, with no server round trip.
Strictness slider with hints
A green-to-red slider bound to the threshold option, with a plain-language hint and an exact readout.
Did you mean
Shows the best match as a one-click correction when it does not literally contain the query.
Category filter chips
Filter the ranked results by category with aria-pressed buttons, combined with the fuzzy search.
Highlighted matches
Matched characters in the name are marked and matching tag chips are tinted, so users see why a result matched.
Relevance meters
includeScore is converted to a percentage meter coloured green, amber or red, plus a Top match badge.
Safe, fast rendering
Every string is HTML-escaped. Search time is shown in milliseconds and stays instant for a few thousand items.
Keyboard, dark mode and polish
/ focuses and Esc clears the field, colours follow prefers-color-scheme, and animation respects reduced motion.

About this UI Snippet

Fuse.js Typo-Tolerant Product Search — HTML, CSS & JavaScript

Screenshot of the Fuse.js Typo-Tolerant Product Search with Threshold Tuning snippet rendered live

Shoppers misspell things constantly, and an exact-match search punishes them for it: "sneekers" returns nothing, so the customer concludes you do not sell sneakers. A fuzzy search closes that gap. Fuse.js scores every item by how closely it approximates the query, so "hedphones", "blutooth speeker" and "mecanical keybord" all find the right products without any dictionary or server round trip. This version wraps Fuse in a complete store-style search page: a big search field with a clear button and "/" shortcut, a "Did you mean" suggestion, category filter chips, product cards with highlighted matches and relevance meters, and dark mode.

Make the threshold visible

The most useful thing this snippet adds is a strictness slider bound to Fuse's threshold option, because that number is the one everyone has to tune and almost nobody understands until they see it. The track is a green-to-red gradient, a live hint translates the value into plain language ("Strict · tiny slips only", "Balanced · forgives 1–2 typos", "Very loose · mostly noise"), and a readout shows the exact figure. At 0 the search demands exact matches. Around 0.3 it forgives a couple of wrong or missing letters. Push it towards 0.8 and unrelated products start matching. Dragging rebuilds the index and re-renders instantly, so the trade-off is visible in seconds instead of by guesswork.

Weighted fields and the multiplication caveat

The fields are weighted to reflect how shoppers search: name carries half the score, tags a quarter, then brand and category. A search for "bluetooth" finds products through their tags even when the word is not in the title. One caveat worth knowing: Fuse combines per-key scores multiplicatively, so a perfect hit in a lightly weighted key (a tag) can still outrank a near-perfect hit in a heavily weighted one (the name) — try "wireless" to see it. Weights nudge ranking rather than dictating it, so always test them against real queries. ignoreLocation is enabled so a hit deep inside a long product name counts the same as one at the start.

Show why a result matched

includeMatches returns character ranges per key. The renderer sorts the ranges, skips overlaps and escapes every piece of text before it touches innerHTML, so a product name with angle brackets cannot break the page. Matches in the name are highlighted with <mark>, and matching tags are tinted, so a product found through "waterproof" visibly shows which tag matched. includeScore returns Fuse's error value, where 0 is a perfect match; each card converts it to a relevance percentage with a small meter coloured green, amber or red, and the first result gets a "Top match" badge.

Did you mean, categories and shortcuts

When the top result's name does not literally contain what was typed, a "Did you mean Wireless Headphones?" link appears, and one click replaces the query with the corrected term. Category chips filter the ranked results without re-running the search logic, so typos and categories combine. The empty state offers a "Loosen strictness" button that sets the slider to 0.5, which is the right remedy. Press / to focus the field and Escape to clear it.

Performance and accessibility

The search runs entirely in memory, so it is instant for catalogues up to a few thousand items (the result count even shows the search time in milliseconds). Beyond that, move the index to a server or a dedicated search service. Result counts are announced through aria-live, the category chips use aria-pressed, controls have focus rings, and prefers-reduced-motion switches the card animation off. For a command-palette style search with the same library, see the Fuse fuzzy command search.

Step by step

How to Use

  1. 1
    Start with a typoThe field opens on "blutooth". Bluetooth Speaker ranks first with a "Top match" badge and a "Did you mean" suggestion, and products tagged bluetooth follow with lower relevance meters.
  2. 2
    Try the other typosClick "sneekers", "blutooth speeker" or "mecanical keybord" and watch the correct product surface with its name highlighted.
  3. 3
    Tighten the strictnessDrag the slider to 0. Typo queries return nothing, the hint reads "Exact matches only", and the empty state offers a Loosen strictness button.
  4. 4
    Loosen it too farDrag to the right end. Unrelated products creep in with low, red relevance meters, and the hint warns "mostly noise".
  5. 5
    Combine with a categoryClick a category chip such as Audio. The same fuzzy results are filtered, and the count updates.
  6. 6
    Search by tagType "waterproof" or "gps". Products match through their tags, and the matching tag chip is tinted. Press / to jump to the field and Esc to clear.

Real-world uses

Common Use Cases

🛒
Store and catalogue search
Give shoppers forgiving search, so a misspelling like sneekers still finds sneakers instead of returning nothing, with category chips to narrow it down.
📚
Help centre article search
Find help articles despite misspellings, using weighted fields so title matches count for more than body text, and a did-you-mean link for near misses.
👥
Directory and contact lookup
Find people in a directory by approximate name, with relevance meters derived from the includeScore option.
💰
Price filtering companion
Combine with a noUiSlider price range filter so fuzzy search and numeric filtering work together.
⌨️
Command palette search
Use the same Fuse options for an app launcher, as in the Fuse fuzzy command search.
🎓
Search relevance learning
Use the strictness slider and its hints as a hands-on way to see how the threshold option changes which results appear.

Got questions?

Frequently Asked Questions

Start around 0.3. Lower is stricter and returns fewer results; higher forgives more typos but adds unrelated matches. The hint under the slider labels each range, and you should tune it against real queries.

includeScore returns an error value where 0 is a perfect match and 1 is a complete mismatch. This snippet converts it to a relevance percentage and a coloured meter.

Each key can have a weight; matches in higher-weighted fields contribute more to the final score. Because Fuse multiplies per-key scores, weights nudge ranking rather than dictate it, so test with real queries.

After searching, the top result is compared with the typed text. If it matched on its name and the name does not contain the query, a button offers that name as a correction. Results found only through a tag do not trigger it. Clicking it sets the query to the full product name.

Without it Fuse prefers matches near the start of a field, which unfairly penalises words later in long product names.

It is fast for a few thousand items in memory, and the snippet shows the search time so you can measure it. For tens of thousands, index server-side with a search engine.

Escape every string before inserting it as HTML, as the esc and mark functions do, or build DOM nodes with textContent.

Yes. Use the JSX, Vue, Angular or Tailwind export buttons on this page to convert the markup and styles. In a framework project install Fuse with npm install fuse.js instead of the CDN tag, build the index with useMemo / computed / a service keyed on the data, and keep the query, strictness and category in state. The index holds no DOM listeners, so nothing needs cleanup on unmount.