Skip to Content
Packages@tsproxy/react

@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-instantsearch

Components

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" }, ]} />

Autocomplete

Sub-elements: Root, Input, List, Item, Highlight

Standalone autocomplete that calls the /api/suggestions endpoint. Works outside of InstantSearch.

<Autocomplete serverUrl="http://localhost:3000" collection="products" placeholder="Search products..." onSelect={(suggestion) => console.log(suggestion)} overrides={{ Input: { props: { className: "w-full border rounded px-3 py-2" } }, List: { props: { className: "absolute bg-white border rounded shadow mt-1 w-full" } }, Item: { props: { className: "px-3 py-2 hover:bg-gray-100 cursor-pointer" } }, }} />

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";
Last updated on