npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luciodale/react-searchable-dropdown

v1.0.4

Published

High performance virtualized React dropdown and combobox. Single and multi select, async search, fuzzy matching, grouping, portal positioning, fully accessible, TypeScript first.

Readme

Documentation  ·  NPM  ·  GitHub

npm version npm downloads bundle size license

Why react-searchable-dropdown

Coming from react-select, downshift, or rolling your own combobox, these are the defaults you get instead of add-ons:

  • Virtualized by default. Handles 100k+ options without plugins. Powered by Virtuoso.
  • Fuzzy search built in. Typo tolerant matching with highlight, backed by match-sorter.
  • Single and multi select share one API. Same generic, same props shape, different mode.
  • Async search as a first class mode. No separate component to import.
  • TypeScript generics end to end. Your option type flows through options, value, setValue, searchOptionKeys.
  • No runtime style engine. className slots plus CSS variables. No emotion in your bundle.
  • ARIA combobox accessibility. Keyboard nav, focus restore, screen reader announcements.

Full comparisons: vs react-select (component camp) · vs Downshift (headless camp)

Accessibility

Follows the ARIA combobox pattern out of the box.

  • role="combobox" on the input with aria-expanded, aria-controls, aria-autocomplete="list".
  • role="listbox" on the option list with aria-activedescendant tracking the highlighted item.
  • Keyboard: arrow keys, Enter to select, Escape to close and restore focus to the trigger, Tab to leave without selecting.
  • Multi select adds Backspace to remove the last chip when the input is empty.
  • Focus is trapped inside the dropdown while open and returned to the trigger on close.
  • Screen reader announcements for filtered result counts as the user types.

Install

npm install @luciodale/react-searchable-dropdown

Quick Start

The minimum to get a searchable, virtualized dropdown with keyboard navigation.

// city-picker.tsx
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"
    />
  );
}

Pass an array of strings, a value, and a setter. You get fuzzy search, virtual scrolling, portal positioning, and full keyboard navigation for free.

Features

  • Virtualized rendering — handles hundreds of thousands of options without breaking a sweat. Only visible items are rendered, powered by Virtuoso.
  • Portal positioning — works inside overflow:hidden containers, modals, and scrollable areas. Floating UI handles the positioning so the dropdown never clips.
  • Fuzzy search filtering — configurable match strategies including exact, starts-with, contains, and acronym. Powered by match-sorter with optional debouncing for large lists.
  • Full keyboard navigation — arrow keys, enter, escape, tab. Multi-select adds backspace to remove the last chip.
  • Single and multi-select — two components with the same API surface. Multi-select manages chips, clear-all, and automatic deduplication.
  • Grouped options — dynamic category headers that recalculate as the user searches. Empty groups disappear automatically.
  • TypeScript genericsSearchableDropdown<T> propagates your option type across searchOptionKeys, setValue, and handleGroups. Discriminated unions enforce that object options require search keys while string options don't.
  • Full styling control — CSS class props, CSS variables, or skip the defaults entirely and bring your own. Custom classes replace defaults, no specificity battles.

Multi Select

Selected items appear as removable chips. The dropdown automatically filters out already-selected options.

// skill-picker.tsx
import { useState } from "react";
import { SearchableDropdownMulti } from "@luciodale/react-searchable-dropdown";
import "@luciodale/react-searchable-dropdown/dist/multi-style.css";

const skills = ["TypeScript", "React", "Node.js", "Python", "Go", "Rust"];

function SkillPicker() {
  const [selected, setSelected] = useState<string[] | undefined>(undefined);

  return (
    <SearchableDropdownMulti
      options={skills}
      values={selected}
      setValues={setSelected}
      deleteLastChipOnBackspace
      placeholder="Select skills..."
    />
  );
}

Backspace with an empty search input removes the last chip. A clear-all button appears when there are selected values.

Object Options with Type Safety

When your options are objects, searchOptionKeys tells the dropdown which fields to search against. TypeScript enforces that only keys from your option type are accepted.

// user-picker.tsx
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"
    />
  );
}

Rename department to team in the User type and TypeScript flags searchOptionKeys immediately. The generics flow through so nothing gets out of sync.

Docs

Full documentation, configuration reference, and live demos at koolcodez.com/projects/react-searchable-dropdown.

License

MIT