Build a typo-tolerant, debounced search box for a listing site using Fuse.js and vanilla JavaScript.
When a directory has hundreds of listings, users want to type "dalas" and still find Dallas. Fuse.js gives you fuzzy matching in a few lines.
I added this to a bank branch directory where people search by city, street, or branch name.
Install
npm install fuse.js
Set up the index
import Fuse from "fuse.js";
const branches = [
{ name: "Chase Bank, Dallas", area: "LBJ and Abrams" },
{ name: "Chase Bank, Chicago", area: "Lawrence and Kedzie" },
{ name: "Chase Bank, Las Vegas", area: "Centennial Crossroads" },
];
const fuse = new Fuse(branches, {
keys: ["name", "area"],
threshold: 0.35,
ignoreLocation: true,
});
Debounce the input
Without it you re-run the search on every keystroke.
function debounce(fn, delay = 200) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
Wire it up
<input id="search" type="search" placeholder="Search by city or street">
<ul id="results"></ul>
const input = document.querySelector("#search");
const list = document.querySelector("#results");
const render = (items) => {
list.replaceChildren(
...items.map(({ item }) => {
const li = document.createElement("li");
li.textContent = `${item.name} (${item.area})`;
return li;
})
);
};
input.addEventListener(
"input",
debounce((e) => {
const q = e.target.value.trim();
render(q ? fuse.search(q).slice(0, 10) : []);
})
);
textContent keeps user input and data from being interpreted as HTML.
Tuning
- Lower
thresholdmeans stricter matching, higher means more forgiving. - Weight important keys:
{ name: "name", weight: 2 }. - For tens of thousands of records, consider a server-side search or a worker thread.
Top comments (0)