@tsproxy/react
Headless React components for search UI with a BaseUI-inspired overrides pattern. Ships unstyled — you control all rendering.
Install
npm install @tsproxy/react @tsproxy/js react-instantsearchComponents
SearchBox
Sub-elements: Root, Form, Input, SubmitButton, ResetButton
<SearchBox
placeholder="Search..."
queryHook={debouncedSearch} // optional: debounce/transform queries
overrides={{
Input: { props: { className: "search-input" } },
SubmitButton: { props: { hidden: true } },
}}
/>Hits
Sub-elements: Root, List, Item
<Hits
hitComponent={({ hit }) => <ProductCard product={hit} />}
overrides={{
List: { props: { className: "grid grid-cols-4 gap-4" } },
}}
/>RefinementList
Sub-elements: Root, List, Item, Label, Checkbox, LabelText, Count
<RefinementList
attribute="category"
overrides={{
Checkbox: { props: { className: "custom-checkbox" } },
Count: { props: { className: "text-gray-400 text-xs" } },
}}
/>Pagination
Sub-elements: Root, List, Item, Link
<Pagination
padding={3}
overrides={{
Link: { props: { className: "px-3 py-1 rounded hover:bg-gray-100" } },
}}
/>Stats
Sub-elements: Root, Text
<Stats
formatText={(nbHits, ms) => `${nbHits} products (${ms}ms)`}
overrides={{
Root: { props: { className: "text-sm text-gray-500" } },
}}
/>SortBy
Sub-elements: Root, Select, Option
<SortBy
items={[
{ value: "products", label: "Relevance" },
{ value: "products/sort/price:asc", label: "Price: Low to High" },
]}
/>NoResults
Sub-elements: Root, Title, Message
<NoResults
title="Nothing found"
message="Try different search terms."
/>HitsSkeleton
Sub-elements: Root, List, Item
<HitsSkeleton
count={8}
overrides={{
List: { props: { className: "grid grid-cols-4 gap-4" } },
}}
/>LocaleSelector
Sub-elements: Root, Select, Option
<LocaleSelector
locales={[
{ code: "en", label: "English" },
{ code: "fr", label: "French" },
]}
/>Overrides System
Every component accepts an overrides prop. Each sub-element can be:
Extended with props:
overrides={{
Input: { props: { className: "my-class", "aria-label": "Search" } },
}}Extended with a function (receives default props):
overrides={{
Item: {
props: (defaultProps) => ({
...defaultProps,
className: `${defaultProps.className} extra-class`,
}),
},
}}Replaced entirely:
overrides={{
Checkbox: {
component: ({ checked, onChange }) => (
<Switch checked={checked} onChange={onChange} />
),
},
}}Types
import type {
Override,
Overrides,
SearchBoxProps,
SearchBoxElements,
HitsProps,
HitsElements,
RefinementListProps,
RefinementListElements,
PaginationProps,
PaginationElements,
StatsProps,
StatsElements,
SortByProps,
SortByElements,
NoResultsProps,
NoResultsElements,
HitsSkeletonProps,
HitsSkeletonElements,
} from "@tsproxy/react";