search-ui
React components and hooks for building fast, customizable search experiences on top of Elasticsearch or any search API.
Repository Health
Technical Analysis
Search UI is Elastic’s toolkit for building search interfaces without reinventing query state management, URL syncing, or facet handling from scratch. @elastic/react-search-ui is the React binding on top of the framework-agnostic @elastic/search-ui core: it wraps a SearchDriver instance in a SearchProvider, then exposes state and actions to components through the withSearch higher-order component, a WithSearch render-prop component, and a useSearch hook.
The library ships ready-made containers for the most common search UI patterns — search box, facets, sorting, paging, paging info, results-per-page, and results lists — each connected directly to driver state so building a working search page is mostly wiring config, not writing state-sync glue. Companion connector packages (Elasticsearch, App Search, Workplace Search, Site Search) plug into the same driver, so switching backends means swapping a connector, not rewriting the UI layer.
Because the driver is decoupled from React, searches, filters, and paging state are captured in the URL by default, making individual result sets shareable and linkable without extra work. Teams adopt it when they want a complete, opinionated search front end quickly, but still want to swap out visual components or connectors as needs change.
What You Get
- SearchProvider + SearchDriver wiring that manages query state, debounced search-as-you-type, and lifecycle without manual effect plumbing
- Pre-built containers for SearchBox, Facet, Sorting, Paging, PagingInfo, ResultsPerPage, Results, and Result
- withSearch higher-order component, WithSearch render-prop component, and useSearch hook for connecting custom components to search state
- Automatic URL syncing so searches, filters, sorting, and paging are shareable via direct links
- Built-in accessibility notifications (A11yNotifications) announcing search and filter changes to screen readers
- A pluggable connector model — Elasticsearch, App Search, Workplace Search, Site Search connectors share the same driver and component API
Common Use Cases
- Adding a full-featured search page (search box, facets, sorting, paging) to a React app backed by Elasticsearch
- Building a faceted product or content catalog search experience with minimal custom state management
- Prototyping a search UI quickly against Elastic App Search or Workplace Search before customizing the visual layer
- Replacing an in-house search-state management layer with a maintained driver that already handles URL sync and accessibility
Under The Hood
Architecture
The library is a thin React binding over a framework-agnostic core: SearchProvider (packages/react-search-ui/src/SearchProvider.tsx) instantiates a SearchDriver from @elastic/search-ui inside a useEffect (deferred so it never runs server-side, since the driver touches window), stores it in SearchContext, and tears it down on unmount. Consumers connect via withSearch (src/withSearch.tsx), a higher-order component that subscribes each wrapped component to driver.subscribeToStateChanges individually — a deliberate choice so state updates re-render only the subtree that needs them rather than the whole provider tree. The pre-built containers (src/containers/Facet.tsx, SearchBox.tsx, Paging.tsx, etc.) are themselves built on useSearch/withSearch and forward to view components from the sibling @elastic/react-search-ui-views package, cleanly separating state wiring from rendering. This layering means the visual layer, the state layer, and the backend connector are all independently swappable.
Tech Stack
TypeScript throughout, targeting React >=16.8 <20 as a peer dependency (kept as external in the package’s tsup build). Built with tsup for dual CJS/ESM output plus type declarations, orchestrated across the monorepo’s packages via Lerna and Yarn workspaces. The package depends directly on @elastic/search-ui (the headless driver) and @elastic/react-search-ui-views (default view components), with no runtime dependency on any specific backend — Elasticsearch, App Search, and Workplace Search are all separate connector packages plugged into the same SearchDriver.
Code Quality
Tests use Jest with jest-environment-jsdom and React Testing Library, covering the provider, context, hooks, and each container individually (src/tests and src/containers/tests), including explicit driver-mocking patterns for state-subscription behavior. TypeScript is used consistently with typed props interfaces per component and shared SearchState/SearchDriverActions types imported from the core package. ESLint (flat config, typescript-eslint recommended + Prettier integration) and Prettier enforce style; CI (search-ui-ci.yml) runs install, lint, test, and build on every push and PR via GitHub Actions.
What Makes It Unique The core design choice — a framework-agnostic driver with React (and other framework) bindings layered on top, rather than a React-only state manager — is what lets the same search logic serve multiple connectors and, per the README, multiple front-end frameworks beyond React. Automatic URL state serialization for search/filter/sort/paging out of the box, plus built-in accessibility announcements wired through every container, are handled for the consumer rather than left as an exercise, which is not typical of comparable component-only search UI kits.