UI libraries / React InstantSearch / Widgets

This is the React InstantSearch v7 documentation. React InstantSearch v7 is the latest version of React InstantSearch and the stable version of React InstantSearch Hooks.

If you were using React InstantSearch v6, you can upgrade to v7.

If you were using React InstantSearch Hooks, you can still use the React InstantSearch v7 documentation, but you should check the upgrade guide for necessary changes.

If you want to keep using React InstantSearch v6, you can find the archived documentation.

Signature
<Menu
  attribute={string}
  // Optional parameters
  limit={number}
  showMore={boolean}
  showMoreLimit={number}
  sortBy={string[] | function}
  transformItems={function}
  classNames={object}
  translations={object}
  ...props={ComponentProps<'div'>}
/>
Import
1
import { Menu } from 'react-instantsearch';

About this widget

<Menu> is a widget that displays a list of facets and lets users choose a single value.

As the <Menu> widget is internally based on a hierarchical refinement, you can not refine on a value including the default separator (>). Instead, you can use the <HierarchicalMenu> widget.

Requirements

Ensure that the attribute provided to the hook is already declared as an attribute for faceting.

You can also create your own UI with useMenu().

Examples

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, Menu } from 'react-instantsearch';

const searchClient = algoliasearch('YourApplicationID', 'YourSearchOnlyAPIKey');

function App() {
  return (
    <InstantSearch indexName="instant_search" searchClient={searchClient}>
      <Menu attribute="categories" />
    </InstantSearch>
  );
}

Props

Parameter Description
attribute
type: string
Required

The name of the attribute in the records.

To avoid unexpected behavior, you can’t use the same attribute prop in a different type of widget.

1
<Menu attribute="categories" />
limit
type: number
default: 10

How many facet values to retrieve.

showMore and showMoreLimit determine the number of facet values to display before clicking the Show more button.

1
2
3
4
<Menu
  // ...
  limit={15}
/>
showMore
type: boolean
default: false

Whether to display a button that expands the number of items.

1
2
3
4
<Menu
  // ...
  showMore={true}
/>
showMoreLimit
type: number

The maximum number of items to display if the widget is showing more than the limit items.

1
2
3
4
<Menu
  // ...
  showMoreLimit={25}
/>
sortBy
type: string[] | (a: FacetValue, b: FacetValue) => number
default: ["isRefined", "name:asc"], or `facetOrdering` if set

How to sort refinements. Must be one or more of the following strings:

  • "count" (same as "count:desc")
  • "count:asc"
  • "count:desc"
  • "name" (same as "name:asc")
  • "name:asc"
  • "name:desc"
  • "isRefined" (same as "isRefined:asc")
  • "isRefined:asc"
  • "isRefined:desc"

You can also use a sort function that behaves like the standard Javascript compareFunction.

If you leave the default setting for this parameter, and you’ve set facetOrdering for this facet in renderingContent, facets are sorted using facetOrdering and use the default order as a fallback.

1
2
3
4
<Menu
  // ...
  sortBy={['count:desc', 'name:asc']}
/>
transformItems
type: (items: object[], metadata: { results: SearchResults }) => object[]

Receives the items and is called before displaying them. Should return a new array with the same shape as the original array. Useful for transforming, removing, or reordering items.

In addition, the full results data is available, which includes all regular response parameters, as well as parameters from the helper (for example disjunctiveFacetsRefinements).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const transformItems = (items) => {
  return items.map((item) => ({
    ...item,
    label: item.label.toUpperCase(),
  }));
};

function Search() {
  return (
    <Menu
      // ...
      transformItems={transformItems}
    />
  );
}
classNames
type: Partial<MenuClassNames>
Optional

The CSS classes you can override and pass to the widget’s elements. It’s useful to style widgets with class-based CSS frameworks like Bootstrap or Tailwind CSS.

  • root: The root element of the widget.
  • noRefinementRoot: The root element when there are no refinements.
  • list: The list element.
  • item: Each item element..
  • selectedItem: The selected item element.
  • link: The link of each item.
  • label: The label of each item.
  • count: The count of each item.
  • showMore: The “Show more” button.
  • disabledShowMore: The disabled “Show more” button.
1
2
3
4
5
6
7
<Menu
  // ...
  classNames={{
    root: 'MyCustomMenu',
    list: 'MyCustomMenuList MyCustomMenuList--subclass',
  }}
/>
translations
type: Partial<MenuTranslations>
Optional

A mapping of keys to translation values.

  • showMoreButtonText: The text for the “Show more” button.
1
2
3
4
5
6
7
8
9
<Menu
  // ...
  showMore
  translations={{
    showMoreButtonText({ isShowingMore }) { 
      return isShowingMore ? 'Show less brands' : 'Show more brands';
    },
  }}
/>
...props
type: React.ComponentProps<'div'>
Optional

Any <div> prop to forward to the root element of the widget.

1
2
3
4
<Menu
  // ...
  className="MyCustomMenu" title="My custom title"
/>

Hook

React InstantSearch let you create your own UI for the <Menu> widget with useMenu(). Hooks provide APIs to access the widget state and interact with InstantSearch.

The useMenu() Hook accepts parameters and returns APIs.

Usage

First, create your React component:

import { useMenu } from 'react-instantsearch';

function CustomMenu(props) {
  const { 
    items,
    createURL,
    refine,
    canRefine,
    isShowingMore,
    toggleShowMore,
    canToggleShowMore,
    sendEvent,
   } = useMenu(props);

  return <>{/* Your JSX */}</>;
}

Then, render the widget:

<CustomMenu {...props} />

Parameters

Hooks accept parameters. You can pass them manually, or forward the props from your custom component.

When you provide a function to Hooks, make sure to pass a stable reference to avoid rendering endlessly (for example, with useCallback()). Objects and arrays are memoized; you don’t need to stabilize them.

Parameter Description
attribute
type: string
Required

The name of the attribute in the records.

To avoid unexpected behavior, you can’t use the same attribute prop in a different type of widget.

1
2
3
const menuApi = useMenu({
  attribute: 'categories',
});
limit
type: number
default: 10

How many facet values to retrieve.

showMore and showMoreLimit determine the number of facet values to display before clicking the Show more button.

1
2
3
4
const menuApi = useMenu({
  // ...
  limit: 5,
});
showMore
type: boolean
default: false

Whether to display a button that expands the number of items.

1
2
3
4
const menuApi = useMenu({
  // ...
  showMore: true,
});
showMoreLimit
type: number

The maximum number of items to display if the widget is showing more than the limit items.

1
2
3
4
const menuApi = useMenu({
  // ...
  showMoreLimit: 20,
});
sortBy
type: string[] | (a: FacetValue, b: FacetValue) => number
default: ["isRefined", "name:asc"], or `facetOrdering` if set

How to sort refinements. Must be one or more of the following strings:

  • "count" (same as "count:desc")
  • "count:asc"
  • "count:desc"
  • "name" (same as "name:asc")
  • "name:asc"
  • "name:desc"
  • "isRefined" (same as "isRefined:asc")
  • "isRefined:asc"
  • "isRefined:desc"

You can also use a sort function that behaves like the standard Javascript compareFunction.

If you leave the default setting for this parameter, and you’ve set facetOrdering for this facet in renderingContent, facets are sorted using facetOrdering and use the default order as a fallback.

1
2
3
4
const menuApi = useMenu({
  // ...
  sortBy: ['count:desc', 'name:asc'],
});
transformItems
type: (items: object[], metadata: { results: SearchResults }) => object[]

Receives the items and is called before displaying them. Should return a new array with the same shape as the original array. Useful for transforming, removing, or reordering items.

In addition, the full results data is available, which includes all regular response parameters, as well as parameters from the helper (for example disjunctiveFacetsRefinements).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const transformItems = (items) => {
  return items.map((item) => ({
    ...item,
    label: item.label.toUpperCase(),
  }));
};

function Menu() {
  const menuApi = useMenu({
    // ...
    transformItems,
  });

  return <>{/* Your JSX */}</>;
}

APIs

Hooks return APIs, such as state and functions. You can use them to build your UI and interact with React InstantSearch.

Parameter Description
items
type: MenuItem[]

The elements that can be refined for the current search results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type MenuItem = {
  /**
   * The value of the menu item.
   */
  value: string;
  /**
   * Human-readable value of the menu item.
   */
  label: string;
  /**
   * Number of matched results after refinement is applied.
   */
  count: number;
  /**
   * Indicates if the menu item is refined.
   */
  isRefined: boolean;
};
createURL
type: (value: string) => string

Creates the next state URL of a selected refinement.

refine
type: (value: string) => string

Applies the selected refinement.

canRefine
type: boolean

Whether a refinement can be applied.

isShowingMore
type: boolean

Whether the menu is displaying all the menu items.

toggleShowMore
type: () => void

Toggles the number of values displayed between limit and showMoreLimit.

canToggleShowMore
type: boolean

Whether the Show more button can be activated, meaning there are enough additional items to display, or already displaying over the limit items.

sendEvent
type: (eventType: string, facetValue: string, eventName?: string) => void

Sends an event to the Insights middleware.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React from 'react';
import { useMenu } from 'react-instantsearch';

function CustomMenu(props) {
  const {
    items,
    refine,
    createURL,
    canToggleShowMore,
    toggleShowMore,
    isShowingMore,
  } = useMenu(props);

  return (
    <>
      <ul>
        {items.map((item) => (
          <li key={item.label}>
            <a
              href={createURL(item.value)}
              onClick={(event) => {
                event.preventDefault();

                refine(item.value);
              }}
              style={{ fontWeight: item.isRefined ? 'bold' : 'normal' }}
            >
              <span>{item.label}</span>
              <span>{item.count}</span>
            </a>
          </li>
        ))}
      </ul>
      {props.showMore && (
        <button disabled={!canToggleShowMore} onClick={toggleShowMore}>
          {isShowingMore ? 'Show less' : 'Show more'}
        </button>
      )}
    </>
  );
}
Did you find this page helpful?