Skip to main content
The 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

items
SortByItem[]
required
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' },
  ],
});
transformItems
(items: SortByItem[]) => SortByItem[]
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

currentRefinement
string
The currently selected index or strategy.
const { currentRefinement } = useSortBy({
  items: [{ value: 'products', label: 'Products' }],
});
console.log(currentRefinement); // "products"
options
Array<{ value: string; label: string }>
All available indices and strategies.
const { options } = useSortBy({
  items: [
    { value: 'products', label: 'Relevant' },
    { value: 'products_price_asc', label: 'Price Low' },
  ],
});
refine
(value: string) => void
Function to switch indices or strategies and trigger a new search.
const { refine } = useSortBy({
  items: [{ value: 'products', label: 'Products' }],
});
refine('products_price_asc');
canRefine
boolean
Whether the widget can be refined.
const { canRefine } = useSortBy({
  items: [{ value: 'products', label: 'Products' }],
});
if (!canRefine) {
  return <p>No sort options available</p>;
}
initialIndex
string
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>
  );
}