Skip to main content
The useToggleRefinement hook provides the logic to build a custom component that toggles a facet filter on and off.

Import

import { useToggleRefinement } from 'react-instantsearch';

Parameters

attribute
string
required
Name of the attribute for faceting (e.g., “free_shipping”).
const { value, refine } = useToggleRefinement({
  attribute: 'free_shipping',
});
on
string | number | boolean | (string | number | boolean)[]
Value to filter on when checked.
const hook = useToggleRefinement({
  attribute: 'free_shipping',
  on: true,
});
off
string | number | boolean | (string | number | boolean)[]
Value to filter on when unchecked.
const hook = useToggleRefinement({
  attribute: 'status',
  on: 'available',
  off: 'out_of_stock',
});

Returns

value
{ isRefined: boolean, count: number | null }
The current toggle state and result count.
const { value } = useToggleRefinement({
  attribute: 'free_shipping',
});
console.log(value.isRefined); // true/false
console.log(value.count);     // Number of results with filter applied
refine
(options?: { isRefined: boolean }) => void
Function to toggle the refinement.
const { refine } = useToggleRefinement({
  attribute: 'free_shipping',
});
refine(); // Toggle the current state
refine({ isRefined: false }); // Explicitly set to off
canRefine
boolean
Whether the refinement can be applied.
const { canRefine } = useToggleRefinement({
  attribute: 'free_shipping',
});
if (!canRefine) {
  return null;
}
createURL
(options: { isRefined: boolean }) => string
Function to create a URL for the toggle state.
sendEvent
SendEventForToggle
Function to send Insights events.

Examples

Basic Toggle

import { useToggleRefinement } from 'react-instantsearch';

function FreeShippingToggle() {
  const { value, refine } = useToggleRefinement({
    attribute: 'free_shipping',
    on: true,
  });

  return (
    <label>
      <input
        type="checkbox"
        checked={value.isRefined}
        onChange={() => refine()}
      />
      Free shipping {value.count !== null && `(${value.count})`}
    </label>
  );
}

Toggle with Switch UI

import { useToggleRefinement } from 'react-instantsearch';

function AvailabilitySwitch() {
  const { value, refine, canRefine } = useToggleRefinement({
    attribute: 'available',
    on: true,
  });

  if (!canRefine) {
    return null;
  }

  return (
    <div className="toggle-switch">
      <span>In stock only</span>
      <button
        onClick={() => refine()}
        className={`switch ${value.isRefined ? 'on' : 'off'}`}
        role="switch"
        aria-checked={value.isRefined}
      >
        <span className="switch-handle" />
      </button>
      {value.count !== null && <span>({value.count})</span>}
    </div>
  );
}

Multiple Toggles

import { useToggleRefinement } from 'react-instantsearch';

function ProductFilters() {
  const freeShipping = useToggleRefinement({
    attribute: 'free_shipping',
    on: true,
  });

  const onSale = useToggleRefinement({
    attribute: 'on_sale',
    on: true,
  });

  const inStock = useToggleRefinement({
    attribute: 'in_stock',
    on: true,
  });

  return (
    <div>
      <h3>Filters</h3>
      <label>
        <input
          type="checkbox"
          checked={freeShipping.value.isRefined}
          onChange={() => freeShipping.refine()}
        />
        Free shipping ({freeShipping.value.count})
      </label>
      <label>
        <input
          type="checkbox"
          checked={onSale.value.isRefined}
          onChange={() => onSale.refine()}
        />
        On sale ({onSale.value.count})
      </label>
      <label>
        <input
          type="checkbox"
          checked={inStock.value.isRefined}
          onChange={() => inStock.refine()}
        />
        In stock ({inStock.value.count})
      </label>
    </div>
  );
}

Toggle with On/Off Values

import { useToggleRefinement } from 'react-instantsearch';

function StatusToggle() {
  const { value, refine } = useToggleRefinement({
    attribute: 'status',
    on: 'available',
    off: 'discontinued',
  });

  return (
    <div>
      <button onClick={() => refine()}>
        {value.isRefined ? 'Show available' : 'Show discontinued'}
      </button>
      {value.count !== null && <span>({value.count} items)</span>}
    </div>
  );
}

Toggle Button

import { useToggleRefinement } from 'react-instantsearch';

function SaleToggle() {
  const { value, refine } = useToggleRefinement({
    attribute: 'on_sale',
    on: true,
  });

  return (
    <button
      onClick={() => refine()}
      className={value.isRefined ? 'active' : ''}
      style={{
        backgroundColor: value.isRefined ? '#e74c3c' : '#ccc',
        color: 'white',
        padding: '10px 20px',
        border: 'none',
        borderRadius: '4px',
      }}
    >
      {value.isRefined ? '✓ ' : ''}On Sale
      {value.count !== null && ` (${value.count})`}
    </button>
  );
}
import { useToggleRefinement } from 'react-instantsearch';
import Link from 'next/link';

function FreeShippingLink() {
  const { value, refine, createURL } = useToggleRefinement({
    attribute: 'free_shipping',
    on: true,
  });

  return (
    <Link
      href={createURL({ isRefined: !value.isRefined })}
      onClick={(e) => {
        e.preventDefault();
        refine();
      }}
      style={{ fontWeight: value.isRefined ? 'bold' : 'normal' }}
    >
      Free shipping ({value.count})
    </Link>
  );
}

TypeScript

import { useToggleRefinement } from 'react-instantsearch';
import type { UseToggleRefinementProps } from 'react-instantsearch';

function FreeShippingToggle(props: UseToggleRefinementProps) {
  const { value, refine } = useToggleRefinement(props);

  return (
    <label>
      <input
        type="checkbox"
        checked={value.isRefined}
        onChange={() => refine()}
      />
      Free shipping
    </label>
  );
}