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

# Integrate Autocomplete with Vue InstantSearch

> Learn how to use Autocomplete with Vue InstantSearch.

<Tip>
  Autocomplete is also available as an experimental widget in InstantSearch,
  making it easier to integrate into your search experience.
  For more information,
  see the API reference for [InstantSearch.js](/doc/api-reference/widgets/autocomplete/js) or
  [React InstantSearch](/doc/api-reference/widgets/autocomplete/react).
</Tip>

When you think of search experiences on sites like Amazon (ecommerce) or YouTube (media),
you may notice that both sites use an autocomplete experience.
It's the autocomplete, and not just a search input, that powers the search page.

If you have an existing Vue InstantSearch implementation,
**you can create a similar experience by adding Autocomplete to your Vue InstantSearch application**.
Adding Autocomplete to an existing Vue InstantSearch implementation lets you enhance the search experience and create a richer,
more contextual search.
You can use context from the current user and how they interacted with your site,
save their recent searches, provide suggested queries, and more.
This autocomplete can work as a rich search box in a search page,
and a portable all-in-one search experience anywhere else on your site.

This guide shows you how to integrate Autocomplete with Vue InstantSearch on your site.

<img src="https://mintcdn.com/algolia/Gja8rtqcY6eJARlr/images/ui-libraries/autocomplete/guides/autocomplete-with-vue-instantsearch.png?fit=max&auto=format&n=Gja8rtqcY6eJARlr&q=85&s=8f70ce2894d6b00419c8bef561c6b795" alt="Screenshot of a search interface with 'air' entered, showing autocomplete suggestions and iPad Air product results." width="1280" height="850" data-path="images/ui-libraries/autocomplete/guides/autocomplete-with-vue-instantsearch.png" />

<Columns>
  <Card title="Open CodeSandbox" icon="codesandbox" href="https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/vue-instantsearch?file=/src/App.vue">
    Run and edit the Autocomplete with Vue InstantSearch example in CodeSandbox.
  </Card>

  <Card title="Explore source code" icon="github" href="https://github.com/algolia/autocomplete/tree/next/examples/vue-instantsearch">
    Browse the source for the Autocomplete with Vue InstantSearch example on GitHub.
  </Card>
</Columns>

This guide starts from a brand new Vue InstantSearch application,
but you can adapt it to integrate Autocomplete in your existing implementation.

## Create a search page with Vue InstantSearch

First, use a starter template for the InstantSearch implementation.
The easiest way to achieve that is to use `create-instantsearch-app`,
a command-line utility that helps to quickly get your app started.

```sh Command line icon=square-terminal theme={"system"}
npx create-instantsearch-app@latest autocomplete-vue-instantsearch \
  --template "Vue InstantSearch with Vue 3" \
  --app-id "latency" \
  --api-key "6be0576ff61c053d5f9a3225e2a90f76" \
  --index-name instant_search \
  --attributes-to-display name,description \
  --attributes-for-faceting categories
```

The template uses a two-column layout with categories on the left and a search box,
hits, and a pagination widget on the right.

Next, set up InstantSearch to enable routing by using the default [`history`](/doc/api-reference/widgets/history-router/vue)
router, which you want to reuse in your Autocomplete integration.
This lets InstantSearch understand query parameters from the URL to derive its state.

```jsx Vue icon=code theme={"system"}
<template>
  <!-- ... -->
  <ais-instant-search
    :search-client="searchClient"
    index-name="instant_search"
    :routing="routing"
  >
    <!-- ... -->
  </ais-instant-search>
  <-- ... -->
</template>

<script>
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { history } from "instantsearch.js/es/lib/routers";
import { singleIndex } from "instantsearch.js/es/lib/stateMappings";

export default {
  data() {
    return {
      searchClient: algoliasearch(
        "latency",
        "6be0576ff61c053d5f9a3225e2a90f76",
      ),
      routing: {
        router: history(),
        stateMapping: singleIndex("instant_search"),
      },
    };
  },
};
</script>
```

You should now have a working Vue InstantSearch application with routing.

## Use Autocomplete as a search box

Vue InstantSearch ships with a [`<ais-search-box>`](/doc/api-reference/widgets/search-box/vue) component, but it doesn't offer autocomplete features like those seen on YouTube and Amazon. Instead, you can replace the `<ais-search-box>` with Algolia's Autocomplete.

With Vue, you can store all the logic of Autocomplete in a single file, and expose it as a component. Start by creating a file called `Autocomplete.vue`. As Autocomplete needs to interact with the InstantSearch state, you can add a mixin to transform it into a [custom Vue InstantSearch widget](/doc/guides/building-search-ui/widgets/create-your-own-widgets/vue).

<CodeGroup>
  ```jsx Vue 3 theme={"system"}
  <template>
    <div ref="autocompleteContainer"></div>
  </template>

  <script lang="jsx">
  import { createWidgetMixin } from "vue-instantsearch/vue3/es";
  import { connectSearchBox } from "instantsearch.js/es/connectors";

  export default {
    mixins: [createWidgetMixin({ connector: connectSearchBox })],
  };
  </script>
  ```

  ```jsx Vue 2 theme={"system"}
  <template>
    <div ref="autocompleteContainer"></div>
  </template>

  <script>
  import { createWidgetMixin } from "vue-instantsearch/vue2/es";
  import { connectSearchBox } from "instantsearch.js/es/connectors";

  export default {
    mixins: [createWidgetMixin({ connector: connectSearchBox })],
  };
  </script>
  ```
</CodeGroup>

You can now add this component into your app.

```jsx Vue icon=code theme={"system"}
<template>
  <!-- ... -->
  <ais-instant-search
    :search-client="searchClient"
    index-name="instant_search"
    :routing="routing"
  >
    <!-- ... -->
    <div class="searchbox">
      <Autocomplete />
    </div>
    <!-- ... -->
  </ais-instant-search>
  <!-- ...-->
</template>

<script>
/* ... */
import Autocomplete from "./Autocomplete.vue";

export default {
  /* ... */
  components: { Autocomplete },
};
</script>
```

Next, you can initialize Autocomplete in the `mounted()` hook of the component's lifecycle. Since it behaves as a custom InstantSearch widget, you have direct access to the underlying InstantSearch instance.

<CodeGroup>
  ```jsx Autocomplete.vue (Vue 3) theme={"system"}
  <script lang="jsx">
  import { h as createElement, Fragment, render } from "vue";

  import { createWidgetMixin } from "vue-instantsearch/vue3/es";
  import { connectSearchBox } from "instantsearch.js/es/connectors";
  import { autocomplete } from "@algolia/autocomplete-js";

  import "@algolia/autocomplete-theme-classic";

  import { INSTANT_SEARCH_INDEX_NAME } from "./constants";

  export default {
    mixins: [createWidgetMixin({ connector: connectSearchBox })],
    mounted() {
      const { instantSearchInstance } = this;

      // Set the InstantSearch index UI state from external events
      function setInstantSearchUiState({ query }) {
        instantSearchInstance.setUiState((uiState) => ({
          ...uiState,
          [INSTANT_SEARCH_INDEX_NAME]: {
            ...uiState[INSTANT_SEARCH_INDEX_NAME],
            // We reset the page when the search state changes
            page: 1,
            query,
          },
        }));
      }

      const initialState =
        instantSearchInstance.mainIndex.getHelper()?.state || {};

      this.autocompleteInstance = autocomplete({
        container: this.$refs.autocompleteContainer,
        placeholder: "Search for products",
        detachedMediaQuery: "none",
        initialState: { query: initialState.query || "" },
        onSubmit({ state }) {
          setInstantSearchUiState({ query: state.query });
        },
        onReset() {
          setInstantSearchUiState({ query: "" });
        },
        onStateChange({ prevState, state }) {
          if (prevState.query !== state.query) {
            setInstantSearchUiState({ query: state.query });
          }
        },
        // Use Vue implementation of createElement and Fragment
        // instead of those provided with Autocomplete
        renderer: { createElement, Fragment, render },
      });
    },
    beforeUnmount() {
      this.autocompleteInstance?.destroy();
    },
  };
  </script>
  ```

  ```jsx Autocomplete.vue (Vue 2) theme={"system"}
  <script>
  import { createWidgetMixin } from "vue-instantsearch/vue2/es";
  import { connectSearchBox } from "instantsearch.js/es/connectors";
  import { autocomplete } from "@algolia/autocomplete-js";

  import "@algolia/autocomplete-theme-classic";

  import { INSTANT_SEARCH_INDEX_NAME } from "./constants";

  export default {
    mixins: [createWidgetMixin({ connector: connectSearchBox })],
    mounted() {
      const { instantSearchInstance } = this;

      // Set the InstantSearch index UI state from external events
      function setInstantSearchUiState({ query }) {
        instantSearchInstance.setUiState((uiState) => ({
          ...uiState,
          [INSTANT_SEARCH_INDEX_NAME]: {
            ...uiState[INSTANT_SEARCH_INDEX_NAME],
            // We reset the page when the search state changes
            page: 1,
            query,
          },
        }));
      }

      const initialState =
        instantSearchInstance.mainIndex.getHelper()?.state || {};

      this.autocompleteInstance = autocomplete({
        container: this.$refs.autocompleteContainer,
        placeholder: "Search for products",
        detachedMediaQuery: "none",
        initialState: { query: initialState.query || "" },
        onSubmit({ state }) {
          setInstantSearchUiState({ query: state.query });
        },
        onReset() {
          setInstantSearchUiState({ query: "" });
        },
        onStateChange({ prevState, state }) {
          if (prevState.query !== state.query) {
            setInstantSearchUiState({ query: state.query });
          }
        },
      });
    },
    beforeDestroy() {
      this.autocompleteInstance?.destroy();
    },
  };
  </script>
  ```

  ```js constants.js theme={"system"}
  export const INSTANT_SEARCH_INDEX_NAME = "instant_search";
  ```
</CodeGroup>

You can now remove the original `<ais-search-box>` component from your Vue InstantSearch implementation.
This replaces the InstantSearch search box with Autocomplete, and acts exactly like before.
But you can now add many more interesting features.

## Add recent searches

When you search on YouTube or Google and come back to the search box later on,
the autocomplete displays your recent searches.
This pattern lets users quickly access content by using the same path they took to find it in the first place.

Add recent searches to Autocomplete with the `@algolia/autocomplete-plugin-recent-searches` package.
It exposes a [`createLocalStorageRecentSearchesPlugin`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-recent-searches/createLocalStorageRecentSearchesPlugin)
function to let you create a recent searches plugin.

<CodeGroup>
  ```jsx Autocomplete.vue (Vue 3) theme={"system"}
  <script lang="jsx">
  import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';

  export default {
    /_... _/
    mounted() {
      /_ ..._/
      const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
        key: 'instantsearch',
        limit: 3,
        transformSource({ source }) {
          return {
            ...source,
            onSelect({ item }) {
              setInstantSearchUiState({ query: item.label });
            },
          };
        },
      });

      /* ... */
      this.autocompleteInstance = autocomplete({
        /* ... */

        // You want recent searches to appear with an empty query
        openOnFocus: true,
        // Add the recent searches plugin
        plugins: [recentSearchesPlugin],

        /* ... */
      });
    },
  };
  </script>
  ```

  ```jsx Autocomplete.vue (Vue 2) theme={"system"}
  <script>
  import { createLocalStorageRecentSearchesPlugin } from "@algolia/autocomplete-plugin-recent-searches";

  export default {
    /* ... */
    mounted() {
      /* ... */
      const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
        key: "instantsearch",
        limit: 3,
        transformSource({ source }) {
          return {
            ...source,
            onSelect({ item }) {
              setInstantSearchUiState({ query: item.label });
            },
          };
        },
      });

      /* ... */
      this.autocompleteInstance = autocomplete({
        /* ... */

        // You want recent searches to appear with an empty query
        openOnFocus: true,
        // Add the recent searches plugin
        plugins: [recentSearchesPlugin],

        /* ... */
      });
    },
  };
  </script>
  ```
</CodeGroup>

<Note>
  Some of this code is abstracted in the following sections to simplify the examples.
</Note>

Since the `recentSearchesPlugin` reads from [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), you can't see any recent searches until you perform at least one query. To submit a search, make sure to press Enter on the query. Once you do, you'll see it appear as a recent search.
For more information, see [Recent searches](/doc/ui-libraries/autocomplete/guides/adding-recent-searches).

## Add Query Suggestions

**The most typical pattern you can see on every autocomplete is suggestions.**
They're predictions of queries that match what users are typing and are guaranteed to return results.
For example, when typing "how to" in Google,
the search engine suggests matching suggestions for users to complete their query.
It's beneficial on mobile devices, where typing is more demanding than a physical keyboard.

Autocomplete lets you add Query Suggestions with the `@algolia/autocomplete-plugin-query-suggestions` package.
It exposes a [`createQuerySuggestionsPlugin`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-query-suggestions/createQuerySuggestionsPlugin)
function to let you create a Query Suggestions plugin.

This plugin requires a [Query Suggestions](/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/js) index.

<CodeGroup>
  ```jsx App.vue theme={"system"}
  <script>
  import { history } from "instantsearch.js/es/lib/routers";
  import { singleIndex } from "instantsearch.js/es/lib/stateMappings";

  import Autocomplete from "./Autocomplete.vue";
  import { INSTANT_SEARCH_INDEX_NAME } from "./constants";
  import { searchClient } from "./searchClient";

  export default {
    components: { Autocomplete },
    data() {
      return {
        searchClient,
        indexName: INSTANT_SEARCH_INDEX_NAME,
        routing: {
          router: history(),
          stateMapping: singleIndex(INSTANT_SEARCH_INDEX_NAME),
        },
      };
    },
  };
  </script>
  ```

  ```jsx Autocomplete.vue (Vue 3) theme={"system"}
  <script lang="jsx">
  import { createQuerySuggestionsPlugin } from "@algolia/autocomplete-plugin-query-suggestions";

  import {
    INSTANT_SEARCH_INDEX_NAME,
    INSTANT_SEARCH_QUERY_SUGGESTIONS,
  } from "./constants";
  import { searchClient } from "./searchClient";

  export default {
    /* ... */
    mounted() {
      /* ... */
      const querySuggestionsPlugin = createQuerySuggestionsPlugin({
        searchClient,
        indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
        getSearchParams() {
          // This creates a shared `hitsPerPage` value once the duplicates
          // between recent searches and Query Suggestions are removed
          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 6,
          });
        },
        transformSource({ source }) {
          return {
            ...source,
            sourceId: "querySuggestionsPlugin",
            onSelect({ item }) {
              setInstantSearchUiState({ query: item.query });
            },
            getItems(params) {
              // We don't display Query Suggestions when there's no query
              if (!params.state.query) {
                return [];
              }

              return source.getItems(params);
            },
          };
        },
      });

      /* ... */
      this.autocompleteInstance = autocomplete({
        /* ... */

        // Add the recent searches plugin and Query Suggestions plugins
        plugins: [recentSearchesPlugin, querySuggestionsPlugin],

        /* ... */
      });
    },
  };
  </script>
  ```

  ```jsx Autocomplete.vue (Vue 2) theme={"system"}
  <script>
  import { createQuerySuggestionsPlugin } from "@algolia/autocomplete-plugin-query-suggestions";

  import {
    INSTANT_SEARCH_INDEX_NAME,
    INSTANT_SEARCH_QUERY_SUGGESTIONS,
  } from "./constants";
  import { searchClient } from "./searchClient";

  export default {
    /* ... */
    mounted() {
      /* ... */
      const querySuggestionsPlugin = createQuerySuggestionsPlugin({
        searchClient,
        indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
        getSearchParams() {
          // This creates a shared `hitsPerPage` value once the duplicates
          // between recent searches and Query Suggestions are removed
          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 6,
          });
        },
        transformSource({ source }) {
          return {
            ...source,
            sourceId: "querySuggestionsPlugin",
            onSelect({ item }) {
              setInstantSearchUiState({ query: item.query });
            },
            getItems(params) {
              // We don't display Query Suggestions when there's no query
              if (!params.state.query) {
                return [];
              }

              return source.getItems(params);
            },
          };
        },
      });

      /* ... */
      this.autocompleteInstance = autocomplete({
        /* ... */

        // Add the recent searches plugin and Query Suggestions plugins
        plugins: [recentSearchesPlugin, querySuggestionsPlugin],

        /* ... */
      });
    },
  };
  </script>
  ```

  ```js constants.js theme={"system"}
  export const INSTANT_SEARCH_INDEX_NAME = "instant_search";
  export const INSTANT_SEARCH_QUERY_SUGGESTIONS =
    "instant_search_demo_query_suggestions";
  ```

  ```js searchClient.js theme={"system"}
  import { liteClient as algoliasearch } from "algoliasearch/lite";

  export const searchClient = algoliasearch(
    "latency",
    "6be0576ff61c053d5f9a3225e2a90f76",
  );
  ```
</CodeGroup>

See also:

* [Suggested searches](/doc/ui-libraries/autocomplete/guides/adding-suggested-searches)
* [Autocomplete Query Suggestions plugin](/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-query-suggestions)

## Debounce search results

Having two sets of results update as you type generates many UI flashes.
This is distracting for users because two distinct sections compete for their attention.

You can mitigate this problem by debouncing search results.

```jsx Vue icon=code theme={"system"}
<script>
/* ... */

function debounce(fn, time) {
  let timerId;

  return function (...args) {
    if (timerId) {
      clearTimeout(timerId);
    }

    timerId = setTimeout(() => fn(...args), time);
  };
}

export default {
  /* ... */
  mounted() {
    /* ... */
    const debouncedSetInstantSearchUiState = debounce(
      setInstantSearchUiState,
      500,
    );

    /* ... */
    this.autocompleteInstance = autocomplete({
      /* ... */
      onStateChange({ prevState, state }) {
        if (prevState.query !== state.query) {
          debouncedSetInstantSearchUiState({ query: state.query });
        }
      },
    });
  },
};
</script>
```

## Support categories in Query Suggestions

**A key feature of Autocomplete is to pre-configure your InstantSearch page.**
The Query Suggestions plugin supports categories that you can use to refine the query and the category in a single interaction.
This pattern brings users to the right category without interacting with the [`ais-hierarchical-menu`](/doc/api-reference/widgets/hierarchical-menu/vue) widget but using Autocomplete.

<Steps>
  <Step title="Filter by category">
    You need to filter by category and support categories in the helpers you created at the beginning:

    <CodeGroup>
      ```jsx App.vue theme={"system"}
      <template>
        <!-- ... -->
        <ais-hierarchical-menu
          :attributes="['hierarchicalCategories.lvl0', 'hierarchicalCategories.lvl1']"
        />
        <!-- ... -->
      </template>
      ```

      ```jsx Autocomplete.vue (Vue 3) theme={"system"}
      <script lang="jsx">
      /* ... */
      export default {
        /* ... */
        mounted() {
          /* ... */
          function setInstantSearchUiState({
            query,
            category,
            resetCategory = false,
          }) {
            let hierarchicalMenu;
            if (resetCategory) {
              hierarchicalMenu = {
                hierarchicalMenu: { [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [] },
              };
            } else if (!category) {
              hierarchicalMenu = {};
            } else {
              hierarchicalMenu = {
                hierarchicalMenu: {
                  [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
                },
              };
            }

            instantSearchInstance.setUiState((uiState) => ({
              ...uiState,
              [INSTANT_SEARCH_INDEX_NAME]: {
                ...uiState[INSTANT_SEARCH_INDEX_NAME],
                page: 1,
                query,
                ...hierarchicalMenu,
              },
            }));
          }
        },
      };
      </script>
      ```

      ```jsx Autocomplete.vue (Vue 2) theme={"system"}
      <script>
      /* ... */
      export default {
        /* ... */
        mounted() {
          /* ... */
          function setInstantSearchUiState({
            query,
            category,
            resetCategory = false,
          }) {
            let hierarchicalMenu;
            if (resetCategory) {
              hierarchicalMenu = {
                hierarchicalMenu: { [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [] },
              };
            } else if (!category) {
              hierarchicalMenu = {};
            } else {
              hierarchicalMenu = {
                hierarchicalMenu: {
                  [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
                },
              };
            }

            instantSearchInstance.setUiState((uiState) => ({
              ...uiState,
              [INSTANT_SEARCH_INDEX_NAME]: {
                ...uiState[INSTANT_SEARCH_INDEX_NAME],
                page: 1,
                query,
                ...hierarchicalMenu,
              },
            }));
          }
        },
      };
      </script>
      ```

      ```js constants.js theme={"system"}
      /* ... */
      export const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE =
        "hierarchicalCategories.lvl0";
      ```
    </CodeGroup>
  </Step>

  <Step title="Send category to the helpers">
    Update the plugins to forward the category to the helpers:

    <CodeGroup>
      ```jsx Autocomplete.vue (Vue 3) theme={"system"}
      <script lang="jsx">
      /* ... */
      export default {
        /* ... */
        mounted() {
          /* ... */
          const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
            key: "instantsearch",
            limit: 3,
            transformSource({ source }) {
              return {
                ...source,
                onSelect({ item }) {
                  setInstantSearchUiState({
                    query: item.label,
                    category: item.category,
                  });
                },
              };
            },
          });

          const querySuggestionsPlugin = createQuerySuggestionsPlugin({
            searchClient,
            indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
            getSearchParams() {
              // This creates a shared `hitsPerPage` value once the duplicates
              // between recent searches and Query Suggestions are removed
              return recentSearchesPlugin.data.getAlgoliaSearchParams({
                hitsPerPage: 6,
              });
            },
            // Add categories to the suggestions
            categoryAttribute: [
              INSTANT_SEARCH_INDEX_NAME,
              "facets",
              "exact_matches",
              INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
            ],
            transformSource({ source }) {
              return {
                ...source,
                sourceId: "querySuggestionsPlugin",
                onSelect({ item }) {
                  setInstantSearchUiState({
                    query: item.query,
                    category: item.__autocomplete_qsCategory,
                  });
                },
                getItems(params) {
                  // We don't display Query Suggestions when there's no query
                  if (!params.state.query) {
                    return [];
                  }

                  return source.getItems(params);
                },
              };
            },
          });
        },
      };
      </script>
      ```

      ```jsx Autocomplete.vue (Vue 2) theme={"system"}
      <script>
      /* ... */
      export default {
        /* ... */
        mounted() {
          /* ... */
          const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
            key: "instantsearch",
            limit: 3,
            transformSource({ source }) {
              return {
                ...source,
                onSelect({ item }) {
                  setInstantSearchUiState({
                    query: item.label,
                    category: item.category,
                  });
                },
              };
            },
          });

          const querySuggestionsPlugin = createQuerySuggestionsPlugin({
            searchClient,
            indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
            getSearchParams() {
              // This creates a shared `hitsPerPage` value once the duplicates
              // between recent searches and Query Suggestions are removed
              return recentSearchesPlugin.data.getAlgoliaSearchParams({
                hitsPerPage: 6,
              });
            },
            // Add categories to the suggestions
            categoryAttribute: [
              INSTANT_SEARCH_INDEX_NAME,
              "facets",
              "exact_matches",
              INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
            ],
            transformSource({ source }) {
              return {
                ...source,
                sourceId: "querySuggestionsPlugin",
                onSelect({ item }) {
                  setInstantSearchUiState({
                    query: item.query,
                    category: item.__autocomplete_qsCategory,
                  });
                },
                getItems(params) {
                  // We don't display Query Suggestions when there's no query
                  if (!params.state.query) {
                    return [];
                  }

                  return source.getItems(params);
                },
              };
            },
          });
        },
      };
      </script>
      ```
    </CodeGroup>
  </Step>

  <Step title="Reset the InstantSearch category">
    Implement the `onReset` function on your Autocomplete instance to also reset the InstantSearch category.

    ```jsx JSX icon=code theme={"system"}
    autocomplete({
      /* ... */
      onReset() {
        setInstantSearchUiState({ query: "", resetCategory: true });
      },
    });
    ```
  </Step>
</Steps>

## Add contextual Query Suggestions

For an even richer Autocomplete experience,
you can pick up the currently active InstantSearch category and provide suggestions for both this specific category and others. This pattern lets you reduce the search scope to the current category,
like an actual department store, or broaden the suggestions to get out of the current category.

<img src="https://mintcdn.com/algolia/Gja8rtqcY6eJARlr/images/ui-libraries/autocomplete/guides/autocomplete-with-instantsearch-current-category.png?fit=max&auto=format&n=Gja8rtqcY6eJARlr&q=85&s=b160688d94624c0e32c46df57db17e58" alt="Query Suggestions with current InstantSearch category" width="1280" height="714" data-path="images/ui-libraries/autocomplete/guides/autocomplete-with-instantsearch-current-category.png" />

First, make sure to set your category attribute as a facet in your Query Suggestions index. In this demo, the attribute to facet is `instant_search.facets.exact_matches.hierarchicalCategories.lvl0.value`.

<CodeGroup>
  ```jsx Autocomplete.vue (Vue 3) theme={"system"}
  <script lang="jsx">
  /* ... */
  export default {
    /* ... */
    mounted() {
      /* ... */
      // Get the current category from InstantSearch
      function getInstantSearchCurrentCategory() {
        const indexRenderState =
          instantSearchInstance.renderState[INSTANT_SEARCH_INDEX_NAME];
        const refinedCategory = indexRenderState?.hierarchicalMenu?.[
          INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE
        ]?.items?.find(({ isRefined }) => isRefined);

        return refinedCategory?.value;
      }

      /* ... */

      // Query Suggestions plugin for the current category
      const querySuggestionPluginInCategory = createQuerySuggestionsPlugin({
        searchClient,
        indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
        getSearchParams() {
          const currentCategory = getInstantSearchCurrentCategory();
          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 3,
            facetFilters: [
              `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:${currentCategory}`,
            ],
          });
        },
        transformSource({ source }) {
          const currentCategory = getInstantSearchCurrentCategory();
          return {
            ...source,
            sourceId: "querySuggestionsPluginInCategory",
            getItems(params) {
              if (!currentCategory) {
                return [];
              }

              return source.getItems(params);
            },
            templates: {
              ...source.templates,
              header({ items }) {
                if (!items.length) {
                  return null;
                }

                return (
                  <Fragment>
                    <span className="aa-SourceHeaderTitle">
                      In {currentCategory}
                    </span>
                    <span className="aa-SourceHeaderLine"></span>
                  </Fragment>
                );
              },
            },
          };
        },
      });

      // Query Suggestions plugin for the other categories
      const querySuggestionsPlugin = createQuerySuggestionsPlugin({
        /* ... */
        getSearchParams() {
          const currentCategory = getInstantSearchCurrentCategory();
          if (!currentCategory) {
            return recentSearchesPlugin.data.getAlgoliaSearchParams({
              hitsPerPage: 6,
            });
          }

          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 3,
            facetFilters: [
              `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:-${currentCategory}`,
            ],
          });
        },
        transformSource({ source }) {
          const currentCategory = getInstantSearchCurrentCategory();

          return {
            ...source,
            /* ... */
            templates: {
              ...source.templates,
              header({ items }) {
                if (!currentCategory || !items.length) {
                  return null;
                }

                return (
                  <Fragment>
                    <span className="aa-SourceHeaderTitle">
                      In other categories
                    </span>
                    <span className="aa-SourceHeaderLine"></span>
                  </Fragment>
                );
              },
            },
          };
        },
      });
    },
  };
  </script>
  ```

  ```jsx Autocomplete.vue (Vue 2) theme={"system"}
  <script>
  /* ... */
  export default {
    /* ... */
    mounted() {
      /* ... */
      // Get the current category from InstantSearch
      function getInstantSearchCurrentCategory() {
        const indexRenderState =
          instantSearchInstance.renderState[INSTANT_SEARCH_INDEX_NAME];
        const refinedCategory = indexRenderState?.hierarchicalMenu?.[
          INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE
        ]?.items?.find(({ isRefined }) => isRefined);

        return refinedCategory?.value;
      }

      /* ... */

      // Query Suggestions plugin for the current category
      const querySuggestionPluginInCategory = createQuerySuggestionsPlugin({
        searchClient,
        indexName: INSTANT_SEARCH_QUERY_SUGGESTIONS,
        getSearchParams() {
          const currentCategory = getInstantSearchCurrentCategory();
          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 3,
            facetFilters: [
              `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:${currentCategory}`,
            ],
          });
        },
        transformSource({ source }) {
          const currentCategory = getInstantSearchCurrentCategory();
          return {
            ...source,
            sourceId: "querySuggestionsPluginInCategory",
            getItems(params) {
              if (!currentCategory) {
                return [];
              }

              return source.getItems(params);
            },
            templates: {
              ...source.templates,
              header({ items, createElement, Fragment }) {
                if (!items.length) {
                  return null;
                }

                return createElement(Fragment, {}, [
                  createElement(
                    "span",
                    { className: "aa-SourceHeaderTitle" },
                    `In ${currentCategory}`,
                  ),
                  createElement("span", { className: "aa-SourceHeaderLine" }),
                ]);
              },
            },
          };
        },
      });

      // Query Suggestions plugin for the other categories
      const querySuggestionsPlugin = createQuerySuggestionsPlugin({
        /* ... */
        getSearchParams() {
          const currentCategory = getInstantSearchCurrentCategory();
          if (!currentCategory) {
            return recentSearchesPlugin.data.getAlgoliaSearchParams({
              hitsPerPage: 6,
            });
          }

          return recentSearchesPlugin.data.getAlgoliaSearchParams({
            hitsPerPage: 3,
            facetFilters: [
              `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:-${currentCategory}`,
            ],
          });
        },
        transformSource({ source }) {
          const currentCategory = getInstantSearchCurrentCategory();

          return {
            ...source,
            /* ... */
            templates: {
              ...source.templates,
              header({ items, createElement, Fragment }) {
                if (!currentCategory || !items.length) {
                  return null;
                }

                return createElement(Fragment, {}, [
                  createElement(
                    "span",
                    { className: "aa-SourceHeaderTitle" },
                    "In other categories",
                  ),
                  createElement("span", { className: "aa-SourceHeaderLine" }),
                ]);
              },
            },
          };
        },
      });
    },
  };
  </script>
  ```
</CodeGroup>

## Next steps

**Autocomplete is now the primary method for users to refine Vue InstantSearch results.**
From now on, you're leveraging the complete Autocomplete ecosystem to bring a state-of-the-art search experience for desktop and mobile.

You can now add Autocomplete everywhere on your site and redirect users to the search page whenever they submit a search or after they select a suggestion.
You can also use context from the current page to personalize the autocomplete experience.
For example, you could display a preview of matching results in a panel for each suggestion and let InstantSearch provide these results once on the search page.

Code examples:

* [Autocomplete with InstantSearch.js](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/instantsearch?file=/src/app.ts)
* [Autocomplete with React InstantSearch](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/react-instantsearch?file=/src/App.tsx)
* [Autocomplete with Vue InstantSearch](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/vue-instantsearch?file=/src/App.vue)
