react-instantsearch-hooks
🚧 This version is not yet production-ready.
React InstantSearch Hooks is an open-source, experimental UI library for React that lets you quickly build a search interface in your front-end application.
Installation
React InstantSearch Hooks is available on the npm registry. It relies on algoliasearch
to communicate with Algolia APIs.
yarn add react-instantsearch-hooks algoliasearch
npm install react-instantsearch-hooks algoliasearch
Getting started
This package exposes Hooks but no UI components (yet!). You're in charge of building components based on the exposed Hooks.
Let's start with a SearchBox
component based on useSearchBox
:
import React, { useEffect, useRef, useState } from 'react';
import { useSearchBox } from 'react-instantsearch-hooks';
export function SearchBox(props) {
const { query, refine, isSearchStalled } = useSearchBox(props);
const [value, setValue] = useState(query);
const inputRef = useRef(null);
function onSubmit(event) {
event.preventDefault();
event.stopPropagation();
if (inputRef.current) {
inputRef.current.blur();
}
}
function onReset(event) {
event.preventDefault();
event.stopPropagation();
setValue('');
if (inputRef.current) {
inputRef.current.focus();
}
}
function onChange(event) {
setValue(event.currentTarget.value);
}
useEffect(() => {
refine(value);
}, [refine, value]);
useEffect(() => {
if (query !== value) {
setValue(query);
}
}, [query]);
return (
<div className="ais-SearchBox">
<form
action=""
className="ais-SearchBox-form"
noValidate
onSubmit={onSubmit}
onReset={onReset}
>
<input
ref={inputRef}
className="ais-SearchBox-input"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
placeholder={props.placeholder}
spellCheck={false}
maxLength={512}
type="search"
value={value}
onChange={onChange}
/>
<button
className="ais-SearchBox-submit"
type="submit"
title="Submit the search query."
>
<svg
className="ais-SearchBox-submitIcon"
width="10"
height="10"
viewBox="0 0 40 40"
>
<path d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"></path>
</svg>
</button>
<button
className="ais-SearchBox-reset"
type="reset"
title="Clear the search query."
hidden={value.length === 0 && !isSearchStalled}
>
<svg
className="ais-SearchBox-resetIcon"
viewBox="0 0 20 20"
width="10"
height="10"
>
<path d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path>
</svg>
</button>
</form>
</div>
);
}
Then, you can create a Hits
component with useHits
:
import React from 'react';
import { useHits } from 'react-instantsearch-hooks';
export function Hits({ hitComponent: Hit, ...props }) {
const { hits } = useHits(props);
return (
<div className="ais-Hits">
<ol className="ais-Hits-list">
{hits.map((hit) => (
<li key={hit.objectID} className="ais-Hits-item">
<Hit hit={hit} />
</li>
))}
</ol>
</div>
);
}
You can now use these components in the InstantSearch
provider:
import React from 'react';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, useConnector } from 'react-instantsearch-hooks';
import { SearchBox } from './SearchBox';
import { Hits } from './Hits';
const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);
function App() {
return (
<InstantSearch indexName="instant_search" searchClient={searchClient}>
<SearchBox />
<Hits />
</InstantSearch>
);
}
You can build any InstantSearch widget using InstantSearch.js connectors with the useConnector
Hook.
API
InstantSearch
The root provider component of all React InstantSearch hooks.
import { InstantSearch } from 'react-instantsearch-hooks';
It accepts all props from the InstantSearch.js instantsearch
widget.
indexName
string
| required
The main index to search into.
<InstantSearch
indexName="instant_search"
>
{}
</InstantSearch>
searchClient
object
| required
Provides a search client to InstantSearch
.
const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);
<InstantSearch
// ...
searchClient={searchClient}
>
{/* Widgets */}
</InstantSearch>;
initialUiState
object
Provides an initial state to your React InstantSearch widgets using InstantSearch.js' uiState
. To provide an initial state, you must add the corresponding widgets to your implementation.
<InstantSearch
initialUiState={{
indexName: {
query: 'phone',
page: 5,
},
}}
>
{}
</InstantSearch>
onStateChange
function
Triggers when the state changes.
When using this option, the instance becomes controlled. This means that you become responsible for updating the UI state with setUiState
.
This is useful to perform custom logic whenever the state changes.
<InstantSearch
onStateChange={({ uiState, setUiState }) => {
setUiState(uiState);
}}
>
{}
</InstantSearch>
stalledSearchDelay
number
| defaults to 200
Defines a time period after which a search is considered stalled. You can find more information in the slow network guide.
<InstantSearch
stalledSearchDelay={500}
>
{}
</InstantSearch>
routing
boolean | object
The router configuration used to save the UI state into the URL, or any client-side persistence. You can find more information in the routing guide.
<InstantSearch
routing={true}
>
{}
</InstantSearch>
suppressExperimentalWarning
boolean
Removes the console warning about the experimental version. Note that this warning is only displayed in development mode.
<InstantSearch
suppressExperimentalWarning={true}
>
{}
</InstantSearch>
Index
The provider component for an Algolia index. It's useful when you want to build a federated search interface.
It accepts all props from the InstantSearch.js index
widget.
indexName
string
| required
The index to search into.
<Index indexName="instant_search">{}</Index>
indexId
string
An identifier for the Index
widget. Providing an indexId
allows different index widgets to target the same Algolia index. It’s especially useful for the routing feature, and lets you find the refinements that match an Index
widget.
<Index
indexId="instant_search"
>
{}
</Index>
useSearchBox
(props: UseSearchBoxProps) => SearchBoxRenderState
Hook to use a search box.
Types
UseSearchBoxProps
type UseSearchBoxProps = {
queryHook?: (query: string, hook: (value: string) => void) => void;
};
SearchBoxRenderState
type SearchBoxRenderState = {
query: string;
refine: (value: string) => void;
clear: () => void;
isSearchStalled: boolean;
};
Example
function SearchBox(props) {
const { query, refine } = useSearchBox(props);
return {
};
}
useHits
(props: UseHitsProps) => HitsRenderState
Hook to use hits.
Types
UseHitsProps
type UseHitsProps = {
escapeHTML?: boolean;
transformItems?: (items: TItem[]) => TItem[];
};
HitsRenderState
type HitsRenderState = {
hits: Hits;
results?: SearchResults;
sendEvent: (eventType: string, hits: Hit | Hits, eventName?: string) => void;
};
Example
function Hits(props) {
const { hits } = useHits(props);
return {
};
}
(props: UseHierarchicalMenuProps) => HierarchicalMenuRenderState
Hook to use a hierarchical menu.
Types
UseHierarchicalMenuProps
type UseHierarchicalMenuProps = {
attributes: string[];
separator?: string;
rootPath?: string | null;
showParentLevel?: boolean;
limit?: number;
showMore?: boolean;
showMoreLimit?: number;
sortBy?: SortBy<HierarchicalMenuItem>;
transformItems?: TransformItems<HierarchicalMenuItem>;
};
HierarchicalMenuRenderState
export type HierarchicalMenuItem = {
value: string;
label: string;
highlighted?: string;
count: number;
isRefined: boolean;
data: HierarchicalMenuItem[] | null;
};
type HierarchicalMenuRenderState = {
items: HierarchicalMenuItem[];
createURL: (value: string) => string;
refine(value: string): void;
sendEvent: (
eventType: string,
facetValue: string,
eventName?: string
) => void;
canRefine: boolean;
canToggleShowMore: boolean;
isShowingMore: boolean;
toggleShowMore: () => void;
};
Example
function HierarchicalMenu(props) {
const { items } = useHierarchicalMenu(props);
return {
};
}
useRefinementList
(props: UseRefinementListProps) => RefinementListRenderState
Hook to use a refinement list.
Types
UseRefinementListProps
type UseRefinementListProps = {
attribute: string;
operator?: 'and' | 'or';
limit?: number;
showMore?: boolean;
showMoreLimit?: number;
sortBy?: SortBy<RefinementListItem>;
escapeFacetValues?: boolean;
transformItems?: TransformItems<RefinementListItem>;
};
RefinementListRenderState
export type RefinementListItem = {
value: string;
label: string;
highlighted?: string;
count: number;
isRefined: boolean;
};
type RefinementListRenderState = {
items: RefinementListItem[];
hasExhaustiveItems: boolean;
createURL: (value: string) => string;
refine(value: string): void;
sendEvent: (
eventType: string,
facetValue: string,
eventName?: string
) => void;
searchForItems: (query: string) => void;
isFromSearch: boolean;
canRefine: boolean;
canToggleShowMore: boolean;
isShowingMore: boolean;
toggleShowMore: () => void;
};
Example
function RefinementList(props) {
const { items } = useRefinementList(props);
return {
};
}
useSortBy
(props: UseSortByProps) => SortByRenderState
Hook to sort by specified indices.
Types
SortByItem
type SortByItem = {
value: string;
label: string;
};
UseSortByProps
type UseSortByProps = {
items: SortByItem[];
transformItems?: TransformItems<SortByItem>;
};
SortByRenderState
type SortByRenderState = {
initialIndex?: string;
currentRefinement: string;
options: SortByItem[];
refine: (value: string) => void;
hasNoResults: boolean;
};
Example
function SortBy(props) {
const { currentRefinement, options, refine } = useSortBy(props);
return {
};
}
useConnector
<TProps, TWidgetDescription>(connector: Connector<TWidgetDescription, TProps>, props: TProps) => TWidgetDescription['renderState']
React Hook to plug an InstantSearch.js connector to React InstantSearch.
Here's an example to use connectMenu
:
import connectMenu from 'instantsearch.js/es/connectors/menu/connectMenu';
import { useConnector } from 'react-instantsearch-hooks';
function useMenu(props) {
return useConnector(connectMenu, props);
}
If you use TypeScript:
import connectMenu, {
MenuConnectorParams,
MenuWidgetDescription,
} from 'instantsearch.js/es/connectors/menu/connectMenu';
import { useConnector } from './useConnector';
type UseMenuProps = MenuConnectorParams;
function useMenu(props: UseMenuProps) {
return useConnector<MenuConnectorParams, MenuWidgetDescription>(
connectMenu,
props
);
}