> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ais-hierarchical-menu

> Shows a hierarchical menu to navigate nested categories.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

```vue Signature theme={"system"}
<ais-hierarchical-menu
  :attributes="string[]"
  // Optional parameters
  :limit="number"
  :show-more="boolean"
  :show-more-limit="number"
  separator="string"
  root-path="string"
  :show-parent-level="boolean"
  :sort-by="string[] | function"
  :transform-items="function"
  :class-names="object"
/>
```

## Import

<Tabs>
  <Tab title="Component">
    To ensure optimal bundle sizes,
    see [Optimize build size](/doc/guides/building-search-ui/going-further/improve-performance/vue#optimize-build-size).

    ```js Vue icon=code theme={"system"}
    import { AisHierarchicalMenu } from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    export default {
      components: {
        AisHierarchicalMenu
      },
      // ...
    };
    ```
  </Tab>

  <Tab title="Plugin">
    This imports all widgets, even the ones you don't use.
    For more information, see [Get started with Vue InstantSearch](/doc/guides/building-search-ui/getting-started/vue).

    ```js JavaScript icon="code" theme={"system"}
    import Vue from "vue";
    import InstantSearch from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    Vue.use(InstantSearch);
    ```
  </Tab>
</Tabs>

<Card title="See this widget in action" icon="monitor-play" href="https://instantsearchjs.netlify.app/stories/vue/?selectedKind=ais-hierarchical-menu" horizontal>
  Preview this widget and its behavior.
</Card>

## About this widget

The `ais-hierarchical-menu` widget displays a hierarchical navigation menu, based on facet attributes.

To create a hierarchical menu:

1. Decide on an appropriate [facet hierarchy](/doc/guides/managing-results/refine-results/faceting#hierarchical-facets)
2. Determine your [`attributes`](#param-attributes) for faceting from the [dashboard](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting-with-dashboard) or with an [API client](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting)
3. Display the UI with the hierarchical menu widget.

To learn more, see [Facet display](/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/vue).

### Requirements

The objects to use in the hierarchical menu must follow this structure:

```json JSON icon=braces theme={"system"}
[
  {
    "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 JSON icon=braces theme={"system"}
[
  {
    "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](#param-separator) option.

<Note>
  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`](/doc/api-reference/widgets/instantsearch/vue#param-future-persist-hierarchical-root-count)
  in [`ais-instant-search`](/doc/api-reference/widgets/instantsearch/vue).
</Note>

## Examples

```vue Vue icon=code theme={"system"}
<ais-hierarchical-menu
  :attributes="[
    'categories.lvl0',
    'categories.lvl1',
    'categories.lvl2',
    'categories.lvl3',
  ]"
/>
```

## Props

<ParamField body="attributes" type="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.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    :attributes="[
      'categories.lvl0',
      'categories.lvl1',
      'categories.lvl2',
      'categories.lvl3',
    ]"
  />
  ```
</ParamField>

<ParamField body="limit" type="number" default={10}>
  The number of facet values to retrieve.
  When you enable the [`show-more`](#param-show-more) feature,
  this is the number of facet values to display before clicking the "Show more" button.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    :limit="20"
  />
  ```
</ParamField>

<ParamField body="show-more" type="boolean" default={false}>
  Whether to display a button that expands the number of items.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    show-more
  />
  ```
</ParamField>

<ParamField body="show-more-limit" type="number" default={20}>
  The maximum number of displayed items (only used when [`show-more`](#param-show-more) is set to `true`).

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    :show-more-limit="30"
  />
  ```
</ParamField>

<ParamField body="separator" type="string" default=">">
  The level separator used in the <Records />.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    separator="-"
  />
  ```
</ParamField>

<ParamField body="root-path" type="string">
  The prefix path to use if the first level is not the root level.

  Make sure to also include the root path in your [UI state](/doc/api-reference/widgets/ui-state/vue),
  for example, by setting [`initial-ui-state`](/doc/api-reference/widgets/instantsearch/vue#param-initial-ui-state).

  ```vue Vue icon=code theme={"system"}
  <ais-instant-search
    // [...]
    :initial-ui-state="{
      YourIndexName: {
        hierarchicalMenu: {
          'categories.lvl0': ['Audio > Home Audio'],
        },
      },
    }"
  >
    <ais-hierarchical-menu
      // [...]
      root-path="Audio > Home Audio"
    />
  </ais-instant-search>
  ```
</ParamField>

<ParamField body="show-parent-level" type="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.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    :show-parent-level="false"
  />
  ```
</ParamField>

<ParamField body="sort-by" type="string[] | function" default="Uses facetOrdering if set, ['name:asc']">
  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`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort).

  If this facet's `facetOrdering` is set in `renderingContent`, and no `sortBy` value is passed to the widget,
  `facetOrdering` is used with default ordering as a fallback.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    :sort-by="['isRefined', 'count:desc']"
  />
  ```
</ParamField>

<ParamField body="transform-items" type="function">
  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](/doc/guides/building-search-ui/going-further/backend-search/in-depth/understanding-the-api-response/)
  and [parameters from the helper](https://community.algolia.com/algoliasearch-helper-js/reference.html#query-parameters),
  such as `disjunctiveFacetsRefinements`.

  ```vue Vue icon=code theme={"system"}
  <template>
    <!-- ... -->
    <ais-hierarchical-menu [...] :transform-items="transformItems" />
  </template>

  <script>
  export default {
    methods: {
      transformItems(items) {
        return items.map((item) => ({
          ...item,
          label: item.label.toUpperCase(),
        }));
      },

      /* or, combined with results */
      transformItems(items, { results }) {
        return items.map((item) => ({
          ...item,
          label: item.isRefined
            ? `${item.label} (page ${results.page + 1}/${results.nbPages})`
            : item.label,
        }));
      },
    },
  };
  </script>
  ```
</ParamField>

<ParamField body="class-names" type="object">
  The [CSS classes you can override](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue#style-your-widgets):

  * `ais-HierarchicalMenu`. The root element of the widget
  * `ais-HierarchicalMenu--noRefinement`. The root element of the widget with no refinement.
  * `ais-HierarchicalMenu-list`. The list of menu items.
  * `ais-HierarchicalMenu-list--child`. The child list of menu items.
  * `ais-HierarchicalMenu-list--lvl0`. The level 0 list of menu items.
  * `ais-HierarchicalMenu-list--lvl1`. The level 1 list of menu items (and so on).
  * `ais-HierarchicalMenu-item`. The menu list item.
  * `ais-HierarchicalMenu-item--selected`. The selected menu list item.
  * `ais-HierarchicalMenu-item--parent`. The menu list item containing children.
  * `ais-HierarchicalMenu-link`. The clickable menu element.
  * `ais-HierarchicalMenu-link--selected`. The clickable element of a selected menu list item.
  * `ais-HierarchicalMenu-label`. The label of each item.
  * `ais-HierarchicalMenu-count`. The count of each item.
  * `ais-HierarchicalMenu-showMore`. The button used to display more categories.
  * `ais-HierarchicalMenu-showMore--disabled`. This button is used to display more categories.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    // [...]
    :class-names="{
      'ais-HierarchicalMenu': 'MyCustomHierarchicalMenu',
      'ais-HierarchicalMenu-list': 'MyCustomHierarchicalMenuList',
    }"
  />
  ```
</ParamField>

## Customize the UI

<ParamField body="default">
  The slot to override the complete DOM output of the widget.

  When you implement this slot,
  none of the other slots will change the output,
  as the default slot surrounds them.

  **Scope**

  * `items: object[]`. The list of available items.
  * `canToggleShowMore: boolean`. Whether users can click the "Show more" button.
  * `isShowingMore: boolean`. Whether the list is expanded.
  * `refine: (value: string) => void`. Sets the path of the hierarchical filter and triggers a new search.
  * `createURL: (value: string) => string`. The function to generate a URL for the next state.
  * `toggleShowMore: () => void`. Toggles the number of displayed values between [`limit`](#param-limit) and [`show-more-limit`](#param-show-more-limit).
  * `sendEvent: (eventType, facetValue) => 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.

    * To learn more, see the [`insights`](/doc/api-reference/widgets/insights/vue) middleware.

    * `eventType: 'click'`

    * `facetValue: string`

  Where each item is an `object` containing:

  * `label: string`. The label of the item.
  * `value: string`. The value of the item.
  * `count: number`. The number results matching this value.
  * `isRefined: boolean`. Whether the item is selected.
  * `data: object[]|null`. The list of children for the current item.

  <CodeGroup>
    ```vue HierarchicalMenu theme={"system"}
    <ais-hierarchical-menu
      :attributes="[
        'categories.lvl0',
        'categories.lvl1',
        'categories.lvl2',
        'categories.lvl3',
      ]"
      show-more
    >
      <template
        v-slot="{
          items,
          canToggleShowMore,
          isShowingMore,
          refine,
          toggleShowMore,
          createURL,
          sendEvent,
        }"
      >
        <hierarchical-menu-list
          :items="items"
          :refine="refine"
          :createURL="createURL"
        />
        <button
          @click="toggleShowMore()"
          :disabled="!canToggleShowMore"
        >
          {{ isShowingMore ? 'Show less' : 'Show more' }}
        </button>
      </template>
    </ais-hierarchical-menu>
    ```

    ```vue HierarchicalMenuList theme={"system"}
    <template functional>
      <ul>
        <li v-for="item in props.items" :key="item.value">
          <a
            :href="props.createURL(item.value)"
            :style="{ fontWeight: item.isRefined ? 'bold' : '' }"
            @click.prevent="props.refine(item.value)"
          >
            {{ item.label }} ({{ item.count }})
          </a>
          <hierarchical-menu-list
            v-if="item.data"
            :items="item.data"
            :refine="props.refine"
            :createURL="props.createURL"
          />
        </li>
      </ul>
    </template>

    <script>
    export default {
      name: "HierarchicalMenuList",
    };
    </script>
    ```
  </CodeGroup>
</ParamField>

<ParamField body="showMoreLabel">
  The slot to override the show more label.

  **Scope**

  * `isShowingMore: boolean`. Whether the list is expanded.

  ```vue Vue icon=code theme={"system"}
  <ais-hierarchical-menu
    :attributes="[
      'categories.lvl0',
      'categories.lvl1',
      'categories.lvl2',
      'categories.lvl3',
    ]"
    show-more
  >
    <template v-slot:showMoreLabel="{ isShowingMore }">
      {{ isShowingMore ? 'Less' : 'More' }}
    </template>
  </ais-hierarchical-menu>
  ```
</ParamField>

## HTML output

### Default

```html HTML icon=code-xml theme={"system"}
<div class="ais-HierarchicalMenu">
  <ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--lvl0">
    <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent ais-HierarchicalMenu-item--selected">
      <a
        class="ais-HierarchicalMenu-link ais-HierarchicalMenu-link--selected"
        href="#"
      >
        <span class="ais-HierarchicalMenu-label">Appliances</span>
        <span class="ais-HierarchicalMenu-count">4,306</span>
      </a>
      <ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--child ais-HierarchicalMenu-list--lvl1">
        <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
          <a class="ais-HierarchicalMenu-link" href="#">
            <span class="ais-HierarchicalMenu-label">Dishwashers</span>
            <span class="ais-HierarchicalMenu-count">181</span>
          </a>
        </li>
        <li class="ais-HierarchicalMenu-item">
          <a class="ais-HierarchicalMenu-link" href="#">
            <span class="ais-HierarchicalMenu-label">Fans</span>
            <span class="ais-HierarchicalMenu-count">91</span>
          </a>
        </li>
      </ul>
    </li>
    <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
      <a class="ais-HierarchicalMenu-link" href="#">
        <span class="ais-HierarchicalMenu-label">Audio</span>
        <span class="ais-HierarchicalMenu-count">1,570</span>
      </a>
    </li>
  </ul>
  <button class="ais-HierarchicalMenu-showMore">Show more</button>
</div>
```

### Without show more

```html HTML icon=code-xml theme={"system"}
<div class="ais-HierarchicalMenu">
  <ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--lvl0">
    <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent ais-HierarchicalMenu-item--selected">
      <a
        class="ais-HierarchicalMenu-link ais-HierarchicalMenu-link--selected"
        href="#"
      >
        <span class="ais-HierarchicalMenu-label">Appliances</span>
        <span class="ais-HierarchicalMenu-count">4,306</span>
      </a>
      <ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--child ais-HierarchicalMenu-list--lvl1">
        <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
          <a class="ais-HierarchicalMenu-link" href="#">
            <span class="ais-HierarchicalMenu-label">Dishwashers</span>
            <span class="ais-HierarchicalMenu-count">181</span>
          </a>
        </li>
        <li class="ais-HierarchicalMenu-item">
          <a class="ais-HierarchicalMenu-link" href="#">
            <span class="ais-HierarchicalMenu-label">Fans</span>
            <span class="ais-HierarchicalMenu-count">91</span>
          </a>
        </li>
      </ul>
    </li>
    <li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
      <a class="ais-HierarchicalMenu-link" href="#">
        <span class="ais-HierarchicalMenu-label">Audio</span>
        <span class="ais-HierarchicalMenu-count">1,570</span>
      </a>
    </li>
  </ul>
  <button
    class="ais-HierarchicalMenu-showMore ais-HierarchicalMenu-showMore--disabled"
    disabled
  >
    Show more
  </button>
</div>
```

<Note>
  If SEO is important for your search page, ensure that your custom HTML is optimized for search engines:

  * Use `<a>` tags with `href` attributes to allow search engine bots to follow links.
  * Use semantic HTML and include [structured data](https://developers.google.com/search/docs/appearance/structured-data) when relevant.

  For more guidance, see the [SEO checklist](/doc/guides/building-search-ui/resources/seo/js).
</Note>
