downshift
Accessible React hooks and a render-prop primitive for building fully custom autocomplete, combobox, select, and multi-select components.
Repository Health
Technical Analysis
Downshift provides the stateful logic behind autocomplete, combobox, select, and tag-group UI without dictating markup or styling. Rather than shipping pre-styled components, it exposes React hooks — useSelect, useCombobox, useTagGroup, and the legacy useMultipleSelection — plus the original Downshift render-prop component, each of which manages state transitions, keyboard navigation, and prop wiring so consuming code can render its own DOM structure.
The library was built to satisfy the WAI-ARIA authoring practices for combobox and listbox patterns, including the ARIA 1.2 combobox specification the hooks were migrated to in v7. It ships with TypeScript typings, Preact and React Native support, and a Docusaurus-based docs site with live examples, making it a common foundation for teams building fully custom dropdown-style inputs instead of depending on a pre-styled UI kit.
What You Get
- useSelect, useCombobox, and useTagGroup hooks that manage open/closed state, highlighted index, keyboard navigation, and ARIA attribute wiring for custom dropdown components
- The original Downshift render-prop component for teams not yet on the hook-based API, sharing the same accessible interaction model
- Prop getters (getInputProps, getItemProps, getMenuProps, getToggleButtonProps, etc.) that attach the right event handlers and ARIA attributes without prescribing any markup
- Full TypeScript typings, Preact interop, and a React Native build target alongside the standard web build
- A stateReducer / reducer escape hatch for intercepting and overriding internal state transitions before they’re applied
Common Use Cases
- Building a fully custom-styled autocomplete search input that still passes WAI-ARIA combobox audits
- Implementing a multi-select or tag input where selected items render as removable chips
- Replacing a native <select> with a custom-styled dropdown that needs keyboard and screen-reader parity with the native element
- Powering design-system dropdown/combobox primitives that other teams compose into product-specific components
Under The Hood
Architecture The core Downshift component (src/downshift.js) implements a class-based state machine handling isOpen/highlightedIndex/inputValue/selectedItem, routed through a stateReducer hook and exposed via prop-getters (getInputProps, getItemProps, getMenuProps, getToggleButtonProps, getRootProps) that attach ARIA attributes and event handlers computed from internal state. The hooks package (src/hooks) reimplements the same primitives on top of React’s useReducer via a shared reducer.ts and useEnhancedReducer/useControlledReducer utilities in src/hooks/utils, with per-hook modules (useSelect, useCombobox, useTagGroup, legacy useMultipleSelection) each supplying their own reducer cases, prop getters, and stateChangeTypes, while cross-cutting concerns (control-prop validation via useControlPropsValidator, scroll-into-view via useScrollIntoView, id generation via useElementIds) live as composable hooks in src/hooks/utils. It’s a layered “core reducer + prop-getter” pattern replicated per widget rather than a single monolith, so changes to the shared reducer/useControlledReducer layer ripple into all four hooks, while adding a new widget mainly means composing the existing utils into a fresh hook.
Tech Stack Runtime dependencies are minimal — @babel/runtime, compute-scroll-into-view, prop-types, react-is, tslib — with react as the sole peer dependency. Build tooling is kcd-scripts driving Babel and Rollup to emit CJS, ESM, and React Native bundles alongside TypeScript declaration-only output for typings/index.d.ts. Docs are built with Docusaurus and deployed via Netlify. Testing runs on Jest for unit/integration coverage plus Playwright for browser-level e2e specs, and CI is a single GitHub Actions workflow (validate.yml) that runs lint, build-and-test, coverage, tsc —noEmit, an SSR check, and the e2e suite on every push.
Code Quality The repo carries extensive test coverage — more than seventy test files under src/**/tests exercising nearly every prop-getter and utility function individually, plus top-level integration tests and Playwright e2e specs driving real browser interaction. tsconfig.json enables strict, strictNullChecks, and noUncheckedIndexedAccess, and the codebase mixes TypeScript with a smaller amount of legacy untyped JavaScript (mainly around the older useMultipleSelection hook). Linting and formatting are centralized via kcd-scripts and enforced through a husky pre-commit hook plus lint-staged, and CI gates every push behind the full validate script.
API Design Downshift’s defining design choice is a fully “headless” API: every interactive element’s props (onClick, onKeyDown, id, role, aria-*) are computed by calling a getter function and spreading the result, so consumers own all markup and styling while still getting ARIA-1.2-compliant combobox/listbox behavior. This predates and directly inspired later headless-UI libraries, and the stateReducer/control-props duality gives two escalation paths — override a single state transition inline, or hand state ownership entirely to an external store — without needing two different APIs. There is a genuine ramp-up cost to internalizing the prop-getter convention, which the project’s own FAQ and migration guides acknowledge directly.
Used by 11 apps in this directory
Actual
Invoicing Finance
Local-first personal finance with envelope budgeting, end-to-end encryption, and multi-device sync — no subscription required.
Arroyo
Data Engineering · Analytics
A distributed stream processing engine written in Rust that lets you write SQL to run stateful, real-time computations over data streams with subsecond results.
Cal.diy
Scheduling
The 100% MIT-licensed, community-driven scheduling platform — self-host your own booking infrastructure with no enterprise strings attached.
CodeSandbox
Code Editors · Developer Tools
Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.
Continue
Developer Tools · AI Development · AI Code Assistants
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.
Grafana
Monitoring · Analytics
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.
OpenHands
AI Code Assistants · AI Development
The self-hosted developer control center for running AI coding agents — locally, in Docker, on VMs, or across cloud backends — with automation workflows for GitHub, Slack, and more.
overleaf
Collaboration · Productivity
Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.
Plasmic
CMS · Low Code Platforms · No Code Platforms
The open-source visual builder that lets teams design React apps and websites with drag-and-drop while integrating seamlessly with your codebase.