Skip to main content
This is the React InstantSearch v7 documentation. If you’re upgrading from v6, see the upgrade guide. If you were using React InstantSearch Hooks, this v7 documentation applies—just check for necessary changes. To continue using v6, you can find the archived documentation.
Signature
<HierarchicalMenu
  attributes={string[]}
  // Optional props
  limit={number}
  showMore={boolean}
  showMoreLimit={number}
  separator={string}
  rootPath={string}
  showParentLevel={boolean}
  sortBy={string[] | function}
  transformItems={function}
  classNames={object}
  translations={object}
  ...props={ComponentProps<'div'>}
/>

Import

JavaScript
import { HierarchicalMenu } from "react-instantsearch";

About this widget

The <HierarchicalMenu> widget displays a hierarchical navigation menu, based on facet attributes. To create a hierarchical menu:
  1. Decide on an appropriate facet hierarchy
  2. Determine your attributes for faceting from the dashboard or with an API client
  3. Display the UI with the hierarchical menu widget.
To learn more, see Facet display.
You can also create your own UI with useHierarchicalMenu.

Requirements

The objects to use in the hierarchical menu must follow this structure:
JSON
[
  {
    "objectID": "321432",
    "name": "lemon",
    "categories.lvl0": "products",
    "categories.lvl1": "products > fruits"
  },
  {
    "objectID": "8976987",
    "name": "orange",
    "categories.lvl0": "products",
    "categories.lvl1": "products > fruits"
  }
]
You can also provide more than one path for each level:
JSON
[
  {
    "objectID": "321432",
    "name": "lemon",
    "categories.lvl0": ["products", "goods"],
    "categories.lvl1": ["products > fruits", "goods > to eat"]
  }
]
By default, the separator is > (with spaces), but you can use a different one by using the separator option.
By default, the count of the refined root level is updated to match the count of the actively refined parent level. Keep the root level count intact by setting persistHierarchicalRootCount in <InstantSearch>.

Examples

JavaScript
import React from "react";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { InstantSearch, HierarchicalMenu } from "react-instantsearch";

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

function App() {
  return (
    <InstantSearch indexName="instant_search" searchClient={searchClient}>
      <HierarchicalMenu
        attributes={[
          "categories.lvl0",
          "categories.lvl1",
          "categories.lvl2",
          "categories.lvl3",
        ]}
      />
    </InstantSearch>
  );
}

Props

attributes
string[]
required
The name of the attributes to generate the menu with. To avoid unexpected behavior, you can’t use the same attribute prop in a different type of widget.
JavaScript
<HierarchicalMenu
  attributes={[
    "categories.lvl0",
    "categories.lvl1",
    "categories.lvl2",
    "categories.lvl3",
  ]}
/>;
limit
number
default:10
The number of facet values to retrieve. When you enable the showMore feature, this is the number of facet values to display before clicking the “Show more” button.
JavaScript
<HierarchicalMenu
  // ...
  limit={5}
/>;
showMore
boolean
default:false
Whether to display a button that expands the number of items.
JavaScript
<HierarchicalMenu
  // ...
  showMore={true}
/>;
showMoreLimit
number
The maximum number of displayed items (only used when showMore is set to true).
JavaScript
<HierarchicalMenu
  // ...
  showMoreLimit={20}
/>;
separator
string
default:""
The level separator used in the records.
JavaScript
<HierarchicalMenu
  // ...
  separator=" / "
/>;
rootPath
string
The prefix path to use if the first level isn’t the root level.Make sure to also include the root path in your UI state, for example, by setting initialUiState or calling setUiState.
JavaScript
<InstantSearch
// ...
initialUiState={{
YourInexName: {
  hierarchicalMenu: {
    "categories.lvl0": ["Computers & Tablets"],
  },
},
}}
>
<HierarchicalMenu
// ...
rootPath="Computers & Tablets"
/>
</InstantSearch>;

showParentLevel
boolean
default:true
Whether to show the siblings of the selected parent level of the current refined value.This option doesn’t impact the root level. All root items are always visible.
JavaScript
<HierarchicalMenu
  // ...
  showParentLevel={false}
/>;
sortBy
string[] | (a: FacetValue, b: FacetValue) => number
default:"['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 give a function that receives items two by two, like JavaScript’s Array.sort.
<HierarchicalMenu
  // ...
  sortBy={["isRefined"]}
/>;
transformItems
(items: object[], metadata: { results: SearchResults }) => object[]
A function that receives the list of items before they are displayed. It should return a new array with the same structure. Use this to transform, filter, or reorder the items.The function also has access to the full results data, including all standard response parameters and parameters from the helper, such as disjunctiveFacetsRefinements.
const transformItems = (items) => {
  return items.map((item) => ({
    ...item,
    label: item.label.toUpperCase(),
  }));
};

function Search() {
  return (
    <HierarchicalMenu
      // ...
      transformItems={transformItems}
    />
  );
}
classNames
Partial<HierarchicalMenuClassNames>
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.
  • parentItem. The parent item of the list.
  • link. The link of each item.
  • selectedItemLink. The link of each selected item element.
  • label. The label of each item.
  • count. The count of each item.
  • showMore. The “Show more” button.
  • disabledShowMore. The disabled “Show more” button.
JavaScript
<HierarchicalMenu
  // ...
  classNames={{
    root: "MyCustomHierarchicalMenu",
    list: "MyCustomHierarchicalMenuList MyCustomHierarchicalMenuList--subclass",
  }}
/>;
translations
Partial<HierarchicalMenuTranslations>
A dictionary of translations to customize the UI text and support internationalization.
  • showMoreButtonText. The text for the “Show more” button.
JavaScript
<HierarchicalMenu
  // ...
  showMore
  translations={{
    showMoreButtonText({ isShowingMore }) {
      return isShowingMore ? "Show less brands" : "Show more brands";
    },
  }}
/>;
...props
React.ComponentProps<'div'>
Any <div> prop to forward to the widget’s root element.
JavaScript
<HierarchicalMenu
  className="MyCustomHierarchicalMenu"
  title="My custom title"
/>;

Hook

React InstantSearch let you create your own UI for the <HierarchicalMenu> widget with useHierarchicalMenu. Hooks provide APIs to access the widget state and interact with InstantSearch. The useHierarchicalMenu Hook accepts parameters and returns APIs. It must be used inside the <InstantSearch> component.

Usage

First, create your React component:
JavaScript
import { useHierarchicalMenu } from "react-instantsearch";

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

  return <>{/*Your JSX*/}</>;
}
Then, render the widget:
JavaScript
<CustomHierarchicalMenu {...props} />;

Parameters

Hooks accept parameters. You can either pass them manually or forward props from a custom component.
When passing functions to Hooks, ensure stable references to prevent unnecessary re-renders. Use useCallback() for memoization. Arrays and objects are automatically memoized.
attributes
string[]
required
The names of the attributes inside the records.To avoid unexpected behavior, you can’t use the same attribute prop in a different type of widget.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  attributes: [
    "categories.lvl0",
    "categories.lvl1",
    "categories.lvl2",
    "categories.lvl3",
  ],
});
separator
string
default:""
The level separator used in the records.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  separator: " - ",
});
rootPath
string
The path to use if the first level isn’t the root level.Make sure to also include the root path in your UI state, for example, by setting initialUiState or calling setUiState.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  rootPath: "Audio > Home Audio",
});
showParentLevel
boolean
default:true
Whether to show the siblings of the selected parent level of the current refined value.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  showParentLevel: false,
});
limit
number
default:10
How many facet values to retrieve.When you enable the showMore feature, this is the number of facet values to display before clicking the Show more button.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  limit: 5,
});
showMore
boolean
default:false
Whether to display a button that expands the number of items.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  showMore: true,
});
showMoreLimit
number
The maximum number of displayed items. Only used when showMore is set to true.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  showMoreLimit: 30,
});
sortBy
string[] | (a: RefinementListItem, b: RefinementListItem) => number
default:"['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.When you don’t set 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.
JavaScript
const hierarchicalMenuApi = useHierarchicalMenu({
  // ...
  sortBy: ["count", "name:asc"],
});
transformItems
(items: object[], metadata: { results: SearchResults }) => object[]
A function that receives the list of items before they are displayed. It should return a new array with the same structure. Use this to transform, filter, or reorder the items.The function also has access to the full results data, including all standard response parameters and parameters from the helper, such as disjunctiveFacetsRefinements.
const transformItems = (items) => {
  return items.map((item) => ({
    ...item,
    label: item.label.toUpperCase(),
  }));
};

function HierarchicalMenu() {
  const hierarchicalMenuApi = useHierarchicalMenu({
    // ...
    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.
items
HierarchicalMenuItem[]
The list of items the widget can display.
TypeScript
type HierarchicalMenuItem = {
  /**
   * 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 refinement is applied.
   */
  isRefined: boolean;
  /**
   * n+1 level of items
   */
  data: HierarchicalMenuItem[] | null;
};
isShowingMore
boolean
Whether the list is expanded.
canToggleShowMore
boolean
Whether users can click the “Show more” button.
canRefine
boolean
Indicates if you can refine the search state.
refine
(value: string) => void
Sets the path of the hierarchical filter and triggers a new search.
sendEvent
(eventType: string, facetValue: string, eventName?: string) => void
The function to send click events.
  • The view event is automatically sent when the facets are rendered.
  • The click event is automatically sent when refine is called.
  • You can learn more about the insights middleware.
  • eventType: 'click'
  • facetValue: string
toggleShowMore
() => void
Toggles the number of displayed values between limit and showMoreLimit.
createURL
(value: string) => string
Generates a URL for the next state.

Example

import React from "react";
import { useHierarchicalMenu } from "react-instantsearch";

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

  return (
    <>
      <HierarchicalList
        items={items}
        onNavigate={refine}
        createURL={createURL}
      />
      {props.showMore && (
        <button disabled={!canToggleShowMore} onClick={toggleShowMore}>
          {isShowingMore ? "Show less" : "Show more"}
        </button>
      )}
    </>
  );
}

function HierarchicalList({ items, createURL, onNavigate }) {
  if (items.length === 0) {
    return null;
  }

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

              onNavigate(item.value);
            }}
            style={{ fontWeight: item.isRefined ? "bold" : "normal" }}
          >
            <span>{item.label}</span>
            <span>{item.count}</span>
          </a>
          {item.data && (
            <HierarchicalList
              items={item.data}
              onNavigate={onNavigate}
              createURL={createURL}
            />
          )}
        </li>
      ))}
    </ul>
  );
}

function isModifierClick(event) {
  const isMiddleClick = event.button === 1;
  return Boolean(
    isMiddleClick ||
      event.altKey ||
      event.ctrlKey ||
      event.metaKey ||
      event.shiftKey,
  );
}
I