The problem
Search filtering sounds simple until you have real users. Some type the exact name. Some type the first few letters. Some type a word from the middle. Some type acronyms. A rigid exact-match filter breaks for most of them.
On the performance side, filtering 100k+ items on every keystroke can freeze the UI if you are not careful. The library handles both problems: flexible match strategies via match-sorter and optional debouncing to keep things smooth.
Filter types
The filterType prop controls how aggressively the search matches. It maps
directly to match-sorter ranking thresholds. The default is CONTAINS, which
matches anywhere in the string.
Available filter types
| Prop | Type | Default | Description |
|---|---|---|---|
CASE_SENSITIVE_EQUAL | Ranking | — | Exact match, case-sensitive. 'London' matches 'London' but not 'london'. |
EQUAL | Ranking | — | Exact match, case-insensitive. 'london' matches 'London'. |
STARTS_WITH | Ranking | — | Matches from the start. 'lon' matches 'London' but not 'Babylon'. |
WORD_STARTS_WITH | Ranking | — | Any word can match from its start. 'yor' matches 'New York'. |
CONTAINS | Ranking | — | Matches anywhere in the string. 'ond' matches 'London'. This is the default. |
ACRONYM | Ranking | — | Matches against first letters of words. 'ny' matches 'New York'. |
MATCHES | Ranking | — | Most permissive. Matches individual characters in order. |
NO_MATCH | Ranking | — | Nothing matches. Useful to disable filtering temporarily. |
<SearchableDropdown
options={cities}
value={city}
setValue={setCity}
filterType="STARTS_WITH"
placeholder="Type the first letters..."
/>Search option keys
When your options are objects, searchOptionKeys tells the filter which
fields to search against. It defaults to ["label"] for object options,
so basic search works out of the box. Pass additional keys to search more fields.
type Product = {
label: string;
value: string;
category: string;
sku: string;
};
// Works without searchOptionKeys — searches "label" by default
<SearchableDropdown
options={products}
value={product}
setValue={setProduct}
placeholder="Search products..."
/>
// Search by name and category, but not by SKU
<SearchableDropdown
options={products}
value={product}
setValue={setProduct}
searchOptionKeys={["label", "category"]}
placeholder="Search products..."
/>
The type system ensures searchOptionKeys only accepts keys that exist on
your option type. If you add a field to your type later, it becomes available as a
search key automatically. If you remove one that's referenced, TypeScript catches it.
Debouncing
For small option lists (under a few thousand), filtering is instant and debouncing is unnecessary. For very large lists (100k+), debouncing prevents the filter from running on every keystroke.
// No debounce (default) — good for small lists
<SearchableDropdown
options={smallList}
value={value}
setValue={setValue}
debounceDelay={0}
/>
// 100ms debounce — good for large lists
<SearchableDropdown
options={hugeList}
value={value}
setValue={setValue}
debounceDelay={100}
/>Controlled search query
By default, the search input is uncontrolled. If you need to read or set the search
query from outside the component, use searchQuery and
onSearchQueryChange.
function ControlledSearch() {
const [value, setValue] = useState<string | undefined>(undefined);
const [query, setQuery] = useState<string | undefined>(undefined);
return (
<>
<p>Current search: {query ?? "none"}</p>
<SearchableDropdown
options={cities}
value={value}
setValue={setValue}
searchQuery={query}
onSearchQueryChange={setQuery}
placeholder="Search..."
/>
</>
);
}Create new option
When the search query doesn't match any option, the dropdown shows a "no match" entry
by default. If createNewOptionIfNoMatch is true (the default), selecting
that entry creates a new option from the search text.
// Disable new option creation
<SearchableDropdown
options={cities}
value={city}
setValue={setCity}
createNewOptionIfNoMatch={false}
dropdownOptionNoMatchLabel="Nothing found"
/>Next steps
- Styling — customize the look and feel
- Multi Select — multi-select specific behavior
- Live demo — try filtering on 100k+ options