useFuzzySearch
Fuzzy search for flat lists powered by Fuse.js.
useFuzzySearch
wraps Fuse.js to provide fast, client-side fuzzy matching for simple lists. It memoizes the index for performance and returns filtered results with a minimal API.
Code
import { Dispatch, SetStateAction, useMemo, useState } from 'react';
import Fuse, { FuseOptionKey } from 'fuse.js';
type UseFuzzySearchOptions<T> = {
searchKeys: FuseOptionKey<T>[];
threshold?: number;
ignoreLocation?: boolean;
};
/**
* A hook that provides fuzzy search functionality for an array of items.
*
* @param items - Array of items to search
* @param options - Search configuration options
* @returns Array containing query state, setter, and filtered items
*/
export function useFuzzySearch<T>(
items: T[],
options: UseFuzzySearchOptions<T> = { searchKeys: [] },
): [string, Dispatch<SetStateAction<string>>, T[], boolean] {
const [query, setQuery] = useState<string>('');
const { searchKeys, threshold = 0.2, ignoreLocation = true } = options;
// Create a memoized Fuse instance
const fuse = useMemo(() => {
return new Fuse(items, {
keys: searchKeys as FuseOptionKey<T>[],
threshold,
ignoreLocation,
});
}, [items, searchKeys, threshold, ignoreLocation]);
// Filter items based on the search query
const filteredItems = useMemo(() => {
if (!query) return items;
return fuse.search(query).map((result) => result.item);
}, [fuse, items, query]);
const isEmpty = useMemo(() => {
return filteredItems.length === 0;
}, [filteredItems]);
return [query, setQuery, filteredItems, isEmpty];
}
Example
- Next.js
- React
- TypeScript
- Tailwind CSS
- Radix UI
- Shadcn UI
Usage
'use client';
import React from 'react';
import { Search } from 'lucide-react';
import { Input } from '@/components/intuitive-ui/(native)/input';
import { useAutoFocusedInput } from '@/hooks/use-auto-focused-input';
import { useFuzzySearch } from '@/hooks/use-fuzzy-search';
import Container from '@/app/repository/[topic]/[slug]/_components/container';
const data = [
'Next.js',
'React',
'TypeScript',
'Tailwind CSS',
'Radix UI',
'Shadcn UI',
];
const BasicExample: React.FC = () => {
const [query, setQuery, results] = useFuzzySearch(data, {
searchKeys: [],
});
const inputRef = useAutoFocusedInput();
return (
<div className="flex flex-col gap-4">
<Container>
<div className="flex flex-col gap-2">
<Input
LeadingIcon={Search}
ref={inputRef}
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search technologies"
className="max-w-sm min-w-sm"
/>
<ul className="min-h-32 list-disc pl-6 text-sm">
{results.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
</Container>
</div>
);
};
export default BasicExample;