What is react-searchable-dropdown?
Dropdowns look easy until you actually try to build one properly. The basic select takes ten minutes. Then you spend a week handling keyboard navigation, virtual scrolling for large lists, portal rendering so it doesn't clip inside overflow containers, search filtering that doesn't lag on 100k items, and multi-select with chip management.
react-searchable-dropdown handles all of that. It gives you two components
(SearchableDropdown and SearchableDropdownMulti) that work out of
the box with zero configuration beyond passing your options and a state setter.
Why this library
Most dropdown libraries fall into two camps. The heavyweight ones ship their own styling system, state management layer, and opinions about how your form should work. The lightweight ones give you a bare listbox and leave keyboard nav, virtualization, and positioning entirely on your plate.
This library sits between those two extremes. It handles the hard parts (virtual scrolling via Virtuoso, portal positioning via Floating UI, fuzzy search via match-sorter, full keyboard navigation) and stays out of your state management, styling system, and form library.
What you get
- Virtualized rendering — handles hundreds of thousands of options without breaking a sweat
- Fuzzy search filtering — configurable match strategies including exact, starts-with, contains, and acronym
- Full keyboard navigation — arrow keys, enter, escape, tab, backspace for multi-select
- Portal positioning — works inside overflow:hidden containers, modals, and scrollable areas
- Grouped options — dynamic category headers that recalculate as the user searches
- Single and multi-select — two variants with the same API surface
- TypeScript generics — types flow through your option types, catching config mistakes at compile time
What you control
- All styling — CSS class props or CSS variables, no specificity battles
- Your own state — just pass value/setValue, no stores or providers
- Custom icons — dropdown toggle, clear buttons, and option labels
- New option creation — optionally let users create options when nothing matches
Installation
npm install @luciodale/react-searchable-dropdownQuick start
The simplest possible dropdown. String options, single select, no configuration beyond the essentials.
import { useState } from "react";
import { SearchableDropdown } from "@luciodale/react-searchable-dropdown";
import "@luciodale/react-searchable-dropdown/dist/single-style.css";
const cities = ["London", "Paris", "Berlin", "Madrid", "Rome", "Amsterdam"];
function CityPicker() {
const [city, setCity] = useState<string | undefined>(undefined);
return (
<SearchableDropdown
options={cities}
value={city}
setValue={setCity}
placeholder="Pick a city"
/>
);
}That's it. You get search filtering, keyboard navigation, virtual scrolling, and portal positioning for free. The default stylesheet gives you a clean dark theme that you can override or replace entirely.
Object options
When your options are objects instead of strings, you tell the dropdown which keys to
search against. TypeScript enforces that searchOptionKeys only accepts keys
that actually exist on your option type.
import { useState } from "react";
import { SearchableDropdown } from "@luciodale/react-searchable-dropdown";
import "@luciodale/react-searchable-dropdown/dist/single-style.css";
type User = {
label: string;
value: string;
department: string;
};
const users: User[] = [
{ label: "Alice", value: "alice", department: "Engineering" },
{ label: "Bob", value: "bob", department: "Design" },
{ label: "Carol", value: "carol", department: "Engineering" },
];
function UserPicker() {
const [user, setUser] = useState<User | undefined>(undefined);
return (
<SearchableDropdown
options={users}
value={user}
setValue={setUser}
searchOptionKeys={["label", "department"]}
placeholder="Search by name or department"
/>
);
}TypeScript all the way down
The library uses conditional types and generics throughout. When you pass string options,
searchOptionKeys is not available (it would be meaningless). When you pass
object options, searchOptionKeys becomes required and only accepts keys from
your object type.
This means TypeScript catches configuration mistakes at compile time rather than runtime.
If you pass an object array but forget searchOptionKeys, you get a type
error. If you misspell a key, you get a type error.
Next steps
- Configuration — all available props at a glance
- Filtering — match strategies, debouncing, and search keys
- Multi Select — chips, clear all, backspace deletion
- Styling — CSS classes, variables, and custom themes
- Live demo — see it working with 100k+ options