useSortBy hook provides the logic to build a custom widget that displays a list of indices or sorting strategies, allowing users to change how hits are sorted.
Import
import { useSortBy } from 'react-instantsearch';
Parameters
Array of objects defining the different indices or strategies to choose from.
const { refine } = useSortBy({
items: [
{ value: 'products', label: 'Most relevant' },
{ value: 'products_price_asc', label: 'Lowest price' },
{ value: 'products_price_desc', label: 'Highest price' },
],
});
Function to transform the items passed to the templates.
const { options } = useSortBy({
items: [
{ value: 'products', label: 'Relevant' },
{ value: 'products_price_asc', label: 'Price: Low to High' },
],
transformItems: (items) =>
items.map((item) => ({
...item,
label: item.label.toUpperCase(),
})),
});
Returns
The currently selected index or strategy.
const { currentRefinement } = useSortBy({
items: [{ value: 'products', label: 'Products' }],
});
console.log(currentRefinement); // "products"
All available indices and strategies.
const { options } = useSortBy({
items: [
{ value: 'products', label: 'Relevant' },
{ value: 'products_price_asc', label: 'Price Low' },
],
});
Function to switch indices or strategies and trigger a new search.
const { refine } = useSortBy({
items: [{ value: 'products', label: 'Products' }],
});
refine('products_price_asc');
Whether the widget can be refined.
const { canRefine } = useSortBy({
items: [{ value: 'products', label: 'Products' }],
});
if (!canRefine) {
return <p>No sort options available</p>;
}
The initially selected index or strategy.
const { initialIndex } = useSortBy({
items: [{ value: 'products', label: 'Products' }],
});
Examples
Basic Dropdown
import { useSortBy } from 'react-instantsearch';
function SortBySelector() {
const { currentRefinement, options, refine } = useSortBy({
items: [
{ value: 'products', label: 'Most relevant' },
{ value: 'products_price_asc', label: 'Lowest price' },
{ value: 'products_price_desc', label: 'Highest price' },
],
});
return (
<div>
<label htmlFor="sort-by">Sort by:</label>
<select
id="sort-by"
value={currentRefinement}
onChange={(e) => refine(e.target.value)}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
}
Radio Button Style
import { useSortBy } from 'react-instantsearch';
function RadioSortBy() {
const { currentRefinement, options, refine } = useSortBy({
items: [
{ value: 'products', label: 'Relevance' },
{ value: 'products_price_asc', label: 'Price: Low to High' },
{ value: 'products_price_desc', label: 'Price: High to Low' },
{ value: 'products_date_desc', label: 'Newest first' },
],
});
return (
<div>
<h3>Sort By</h3>
{options.map((option) => (
<label key={option.value} style={{ display: 'block' }}>
<input
type="radio"
name="sort"
value={option.value}
checked={currentRefinement === option.value}
onChange={(e) => refine(e.target.value)}
/>
{option.label}
</label>
))}
</div>
);
}
Button Group
import { useSortBy } from 'react-instantsearch';
function SortByButtons() {
const { currentRefinement, options, refine } = useSortBy({
items: [
{ value: 'products', label: 'Relevant' },
{ value: 'products_price_asc', label: '↑ Price' },
{ value: 'products_price_desc', label: '↓ Price' },
],
});
return (
<div className="sort-buttons">
{options.map((option) => (
<button
key={option.value}
onClick={() => refine(option.value)}
className={currentRefinement === option.value ? 'active' : ''}
>
{option.label}
</button>
))}
</div>
);
}
With Icons
import { useSortBy } from 'react-instantsearch';
const sortIcons = {
products: '🔥',
products_price_asc: '⬆️',
products_price_desc: '⬇️',
products_date_desc: '🆕',
};
function SortByWithIcons() {
const { currentRefinement, options, refine } = useSortBy({
items: [
{ value: 'products', label: 'Most relevant' },
{ value: 'products_price_asc', label: 'Price ascending' },
{ value: 'products_price_desc', label: 'Price descending' },
{ value: 'products_date_desc', label: 'Newest' },
],
});
return (
<select
value={currentRefinement}
onChange={(e) => refine(e.target.value)}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{sortIcons[option.value]} {option.label}
</option>
))}
</select>
);
}
Compact Dropdown
import { useSortBy } from 'react-instantsearch';
function CompactSortBy() {
const { currentRefinement, options, refine } = useSortBy({
items: [
{ value: 'products', label: 'Relevant' },
{ value: 'products_price_asc', label: 'Price ↑' },
{ value: 'products_price_desc', label: 'Price ↓' },
],
});
const currentLabel = options.find(
(option) => option.value === currentRefinement
)?.label;
return (
<div className="compact-sort">
<span>Sort: </span>
<select
value={currentRefinement}
onChange={(e) => refine(e.target.value)}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
}
TypeScript
import { useSortBy } from 'react-instantsearch';
import type { UseSortByProps } from 'react-instantsearch';
function SortBySelector(props: UseSortByProps) {
const { currentRefinement, options, refine } = useSortBy(props);
return (
<select
value={currentRefinement}
onChange={(e) => refine(e.target.value)}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
}