Skip to main content
The useRefinementList hook provides the logic to build custom refinement list (multi-select facet) components.

Import

import { useRefinementList } from 'react-instantsearch';

Parameters

attribute
string
required
The attribute to create the refinement list for.
const { items, refine } = useRefinementList({ attribute: 'brand' });
operator
'and' | 'or'
default:"'or'"
How to combine refinements.
// AND: Results must match all selected values
const hook = useRefinementList({ 
  attribute: 'brand', 
  operator: 'and' 
});

// OR: Results match any selected value
const hook2 = useRefinementList({ 
  attribute: 'color', 
  operator: 'or' 
});
limit
number
default:"10"
Maximum number of items to display.
const { items } = useRefinementList({ 
  attribute: 'brand', 
  limit: 5 
});
showMore
boolean
default:"false"
Whether to enable the “show more” functionality.
const { toggleShowMore, canToggleShowMore } = useRefinementList({ 
  attribute: 'brand', 
  showMore: true,
  showMoreLimit: 20
});
showMoreLimit
number
default:"20"
Maximum number of items to display when “show more” is active.
const hook = useRefinementList({ 
  attribute: 'brand', 
  showMore: true,
  showMoreLimit: 50
});
sortBy
string[] | (a, b) => number
How to sort the facet values.
// Predefined sort orders
const hook = useRefinementList({ 
  attribute: 'brand',
  sortBy: ['isRefined', 'count:desc', 'name:asc']
});

// Custom sort function
const hook2 = useRefinementList({ 
  attribute: 'brand',
  sortBy: (a, b) => a.name.localeCompare(b.name)
});
escapeFacetValues
boolean
default:"true"
Whether to escape facet values.
const hook = useRefinementList({ 
  attribute: 'category',
  escapeFacetValues: false 
});
transformItems
(items: RefinementListItem[]) => RefinementListItem[]
Function to transform the items.
const { items } = useRefinementList({
  attribute: 'brand',
  transformItems: (items) => 
    items.filter((item) => item.count > 0)
});

Returns

items
RefinementListItem[]
The list of refinement values.
const { items } = useRefinementList({ attribute: 'brand' });

items.forEach((item) => {
  console.log(item.value);      // "Apple"
  console.log(item.label);      // "Apple"
  console.log(item.count);      // 42
  console.log(item.isRefined);  // true/false
  console.log(item.highlighted); // "<mark>App</mark>le"
});
refine
(value: string) => void
Function to toggle a refinement.
const { refine } = useRefinementList({ attribute: 'brand' });
refine('Apple'); // Toggle "Apple" refinement
searchForItems
(query: string) => void
Function to search within facet values.
const { searchForItems } = useRefinementList({ attribute: 'brand' });
searchForItems('app'); // Search for brands containing "app"
Whether the current items are from a facet search.
const { isFromSearch } = useRefinementList({ attribute: 'brand' });
canRefine
boolean
Whether refinements can be applied.
const { canRefine } = useRefinementList({ attribute: 'brand' });
canToggleShowMore
boolean
Whether the “show more” toggle is available.
const { canToggleShowMore } = useRefinementList({ 
  attribute: 'brand',
  showMore: true 
});
isShowingMore
boolean
Whether “show more” is currently active.
const { isShowingMore } = useRefinementList({ 
  attribute: 'brand',
  showMore: true 
});
toggleShowMore
() => void
Function to toggle between showing more/less items.
const { toggleShowMore } = useRefinementList({ 
  attribute: 'brand',
  showMore: true 
});
hasExhaustiveItems
boolean
Whether all possible facet values are displayed.
const { hasExhaustiveItems } = useRefinementList({ attribute: 'brand' });
createURL
(value: string) => string
Function to create a URL for a facet value.
const { createURL } = useRefinementList({ attribute: 'brand' });
const url = createURL('Apple');
sendEvent
SendEventForFacet
Function to send Insights events.
const { sendEvent } = useRefinementList({ attribute: 'brand' });
sendEvent('click', 'Apple', 'Brand Filter Clicked');

Examples

Basic Refinement List

import { useRefinementList } from 'react-instantsearch';

function BrandFilter() {
  const { items, refine } = useRefinementList({ attribute: 'brand' });

  return (
    <div>
      <h3>Brands</h3>
      <ul>
        {items.map((item) => (
          <li key={item.value}>
            <label>
              <input
                type="checkbox"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              {item.label} ({item.count})
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}
import { useRefinementList } from 'react-instantsearch';
import { useState } from 'react';

function SearchableBrandFilter() {
  const { items, refine, searchForItems } = useRefinementList({ 
    attribute: 'brand' 
  });
  const [query, setQuery] = useState('');

  const handleSearchChange = (e) => {
    const value = e.target.value;
    setQuery(value);
    searchForItems(value);
  };

  return (
    <div>
      <h3>Brands</h3>
      <input
        type="search"
        value={query}
        onChange={handleSearchChange}
        placeholder="Search brands..."
      />
      <ul>
        {items.map((item) => (
          <li key={item.value}>
            <label>
              <input
                type="checkbox"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              <span dangerouslySetInnerHTML={{ __html: item.highlighted }} />
              {' '}({item.count})
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}

With Show More

import { useRefinementList } from 'react-instantsearch';

function ExpandableBrandFilter() {
  const { 
    items, 
    refine, 
    toggleShowMore, 
    isShowingMore, 
    canToggleShowMore 
  } = useRefinementList({ 
    attribute: 'brand',
    limit: 5,
    showMore: true,
    showMoreLimit: 20
  });

  return (
    <div>
      <h3>Brands</h3>
      <ul>
        {items.map((item) => (
          <li key={item.value}>
            <label>
              <input
                type="checkbox"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              {item.label} ({item.count})
            </label>
          </li>
        ))}
      </ul>
      {canToggleShowMore && (
        <button onClick={toggleShowMore}>
          {isShowingMore ? 'Show less' : 'Show more'}
        </button>
      )}
    </div>
  );
}

Custom Styling

import { useRefinementList } from 'react-instantsearch';

function StyledBrandFilter() {
  const { items, refine } = useRefinementList({ attribute: 'brand' });

  return (
    <div className="refinement-list">
      <h3>Brands</h3>
      <div className="refinement-items">
        {items.map((item) => (
          <button
            key={item.value}
            onClick={() => refine(item.value)}
            className={`refinement-item ${item.isRefined ? 'active' : ''}`}
          >
            <span className="label">{item.label}</span>
            <span className="count">{item.count}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

Sorted by Count

import { useRefinementList } from 'react-instantsearch';

function PopularBrandsFilter() {
  const { items, refine } = useRefinementList({ 
    attribute: 'brand',
    sortBy: ['count:desc', 'name:asc'],
    limit: 10
  });

  return (
    <div>
      <h3>Popular Brands</h3>
      <ul>
        {items.map((item) => (
          <li key={item.value}>
            <label>
              <input
                type="checkbox"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              {item.label} ({item.count})
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}

With Transform

import { useRefinementList } from 'react-instantsearch';

function FilteredBrandList() {
  const { items, refine } = useRefinementList({
    attribute: 'brand',
    transformItems: (items) => 
      items
        .filter((item) => item.count > 5) // Only show brands with >5 items
        .map((item) => ({
          ...item,
          label: item.label.toUpperCase(), // Transform labels
        })),
  });

  return (
    <div>
      <h3>Brands (5+ items)</h3>
      <ul>
        {items.map((item) => (
          <li key={item.value}>
            <label>
              <input
                type="checkbox"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              {item.label} ({item.count})
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}

Build docs developers (and LLMs) love