Centralized state management for search forms.
Strict typing, cross-field validations, and automatic synchronization with the URL or any persistence mechanism.
With Material UI
pnpm add @vaened/mui-search-builderHeadless / Custom UI
pnpm add @vaened/react-search-builderAdvanced search forms usually require:
- Bidirectional synchronization between multiple inputs.
- Cross-field validations (ranges, field dependencies).
- Manual parsing of query strings.
- Constant conversion between string, number, Date, etc.
- State persistence across reloads or navigation.
In practice, this logic often ends up scattered across components, effects, and ad-hoc utilities.
React Search Builder centralizes all these responsibilities into a single Store.
A typical Customer Search form with URL persistence, mixed filter types, and an active filters summary.
conststore=useSearchStore({persistInUrl: true});<SearchFormstore={store}onSearch={console.log}spacing={2}><DateRangeFilterstartFieldName="createdFrom"endFieldName="createdTo"startFieldLabel="Created from"endFieldLabel="Created to"/><DateFiltername="lastActivityAt"label="Last activity"/><OptionSelecttype="string[]"name="channels"label="Acquisition channels"items={{web: "Website",referral: "Referral",partner: "Partner"}}/><SearchBarindexes={{fullName: "Name",email: "Email",document: "Document"}}flags={{isActive: "Active",hasDebt: "Has debt",isVip: "VIP"}}defaultIndex="fullName"/><ActiveFiltersBarlimitTags={8}/></SearchForm>;The project is split into two complementary packages:
@vaened/react-search-builder(Core)
Pure logic and state management. Use it if you want to build your own UI or integrate the system into an existing component library. Detailed package README: packages/react/README.mdUniversal Integration (
FilterFieldController): Connect any UI component (from a simple native<input/>to complex selectors from libraries like AntD or Chakra). You getvalue,onChange, anderrorsready to use.Asynchronous Hydration: Support for async serializers that pause initialization until data is ready and verified, preventing inconsistent states.
Declarative Validation: Define complex conditional and cross-field business rules using the
whenfunction, keeping your components clean of if/else logic.Performance: When typing in a field, only that component updates. The rest of the form stays static. This keeps the UI smooth even with dozens of filters, avoiding unnecessary re-renders across the app.
Data Humanization: Turn technical values (IDs, codes) into user-friendly text. Ideal for filter summaries or search “chips”.
@vaened/mui-search-builder(UI Kit)
Ready-to-use components based on Material UI. Designed for the most common use cases in admin dashboards and backoffice apps. Detailed package README: packages/mui/README.mdUnified SearchBar: A composed component that integrates three features into one visual row:
- Query Input: With automatic debounce.
- Index Select: Lets the user change the search criterion without taking extra UI space.
- Flags: Quick boolean filters integrated visually.
Validated DateRangeFilter: Abstracts the complexity of handling two DatePickers. It automatically enforces range constraints: selecting a start date disables earlier days in the end date, and vice versa, ensuring a valid range.
Polymorphic OptionSelect: A flexible wrapper around MUI Select that accepts multiple data shapes. You can pass a simple dictionary or an array of complex objects with accessors (getValue, getLabel), removing the need for manual
.map()in JSX.Reactive ActiveFiltersBar: Closes the UX loop by visually showing applied filters. Users can remove individual filters or clear everything with one click, automatically syncing with the URL and the Store.
State lives completely decoupled from React’s component tree.
Atomic Subscriptions
Each field subscribes individually to the Store. Typing in an input does not re-render the whole form—only the affected component.Inversion of Control
Enables communication between sibling components (for example, a Country selector clearing a City selector) without prop drilling.
Internally, it guarantees concurrent consistency through
useSyncExternalStore.The storage mechanism is completely agnostic to business logic.
Interchangeable Adapters
WindowUrlPersistenceAdapter(included) syncs withwindow.location, but the architecture supports async adapters for Next.js, React Router, or storage in LocalStorage.Smart Hydration
The Store manages loading states (isHydrating) and task queues (TaskMonitor), ensuring the form is not interactive until the URL has been parsed and validated correctly.
Automatic and transparent data transformation between the persistence layer and the application layer.
Declarative Definition
Configure fields asdate,number,boolean, or array variants (number[],string[]).Type Inference
TypeScript automatically infers the value type returned by hooks based on the field configuration.
Validation rules are pure and executed in the Store, not in the UI.
Composed Rules Native support for complex validation strategies (
allOfwithfailFastor error collection).Domain Validations
- Structural:
required,length - Relational:
range,after,before(cross-field validation between dates or numbers) - Conditional:
when(run validations on field A only if field B matches a condition)
- Structural:
This repository provides a headless core and a ready-to-use Material UI implementation.
Each package has its own detailed documentation:
Core (Headless)
@vaened/react-search-builder
Architecture, store, hooks, validation system, and persistence adapters.
See: packages/react/README.md
Material UI Kit
@vaened/mui-search-builder
Prebuilt components and real-world examples using Material UI.
See: packages/mui/README.md
Use the Core package if you need full control over the UI.
Use the MUI package if you use Material UI and want a set of ready-to-use components.
This library is licensed under the MIT license. For more information, see the license file.