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

# Build a Query Suggestions UI

> Build a user interface to show Query Suggestions in your Vue InstantSearch app.

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>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">Vue</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/tutorials/building-query-suggestions-ui/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/tutorials/building-query-suggestions-ui/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/tutorials/building-query-suggestions-ui/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/tutorials/building-query-suggestions-ui/ios"><span className="afs-option-name">iOS</span><span className="afs-option-lib">InstantSearch iOS</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/tutorials/building-query-suggestions-ui/android"><span className="afs-option-name">Android</span><span className="afs-option-lib">InstantSearch Android</span></a></li>
    </ul>
  </div>
</div>

To help users with their search, Algolia provides [Query Suggestions](/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/js).
This feature creates an <Index /> of your user's best queries.
You can then use this index to propose suggestions to your users as they're typing into the [`ais-search-box`](/doc/api-reference/widgets/search-box/vue).
Once you've configured the generation of the Query Suggestions index, you need to query this index as well.
Use [multi-index search](/doc/guides/building-search-ui/ui-and-ux-patterns/multi-index-search/js) to do that.

This guide shows how to use a search box to display a list of suggestions and their associated categories.
Once users select a suggestion, Algolia will apply the query *and* the category.

If you're building an autocomplete with Query Suggestions,
**you should use the Autocomplete library which lets you build a full-featured,
accessible autocomplete experience.**
This is the recommended way of building an autocomplete search with Algolia.

For more information, see:

* [What is Autocomplete?](/doc/ui-libraries/autocomplete/introduction/what-is-autocomplete)
* [Integrate Autocomplete with Vue InstantSearch](/doc/ui-libraries/autocomplete/integrations/with-vue-instantsearch)
* [Using Autocomplete with Vue](/doc/ui-libraries/autocomplete/integrations/using-vue)
* [Build a Query Suggestions UI with Autocomplete](/doc/ui-libraries/autocomplete/guides/adding-suggested-searches)

## Working example

<Columns>
  <Card title="Open CodeSandbox" icon="codesandbox" href="https://codesandbox.io/s/github/algolia/doc-code-samples/tree/master/vue-instantsearch/query-suggestions">
    Run and edit the Query Suggestions UI example in CodeSandbox.
  </Card>

  <Card title="Explore source code" icon="github" href="https://github.com/algolia/doc-code-samples/tree/master/vue-instantsearch/query-suggestions">
    Browse the source for the Query Suggestions UI example on GitHub.
  </Card>
</Columns>

<Note>
  This code has been specifically created for Vue 2.
  Some [modifications](https://v3-migration.vuejs.org) may be required for it to work correctly in Vue 3.
</Note>

## Refine your results with suggestions

To set up multi-index search experience so users can select a suggestion and use it to search the main index:

<Steps>
  <Step title="Set up custom autocomplete component">
    Set up a custom autocomplete component with the
    [Vue Autosuggest](https://github.com/educents/vue-autosuggest) library.
  </Step>

  <Step title="Wrap the conponent in the connector">
    Wrap the autocomplete component with the [`ais-autocomplete`](/doc/api-reference/widgets/autocomplete/vue) connector.
    For more infomation, see [Autocomplete](/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete/vue).

    ```vue Vue icon=code theme={"system"}
    <template>
      <ais-instant-search
        :search-client="searchClient"
        index-name="instant_search_demo_query_suggestions"
      >
        <ais-configure :hitsPerPage="5" />
        <ais-autocomplete>
          <template v-slot="{ currentRefinement, indices, refine }">
            <vue-autosuggest
              :suggestions="indicesToSuggestions(indices)"
              @selected="onSelect"
              :input-props="{
                style: 'width: 100%',
                onInputChange: refine,
                placeholder: 'Search here...',
              }"
            >
              <template v-slot="{ suggestion }">
                <ais-highlight attribute="query" :hit="suggestion.item" />
              </template>
            </vue-autosuggest>
          </template>
        </ais-autocomplete>
      </ais-instant-search>
    </template>

    <script>
    import { VueAutosuggest } from 'vue-autosuggest';

    export default {
      components: { VueAutosuggest },
      methods: {
        onSelect(selected) {
          if (selected) {
            console.log('selected');
          }
        },
        indicesToSuggestions(indices) {
          return indices.map(({ hits }) => ({
            data: hits.map(hit => {
              return {
                ...hit,
                // this is for Vue AutoSuggest
                name: hit.query,
              };
            }),
          }));
        },
      },
    };
    </script>
    ```
  </Step>

  <Step title="Create the multi-index search experience">
    The [`ais-autocomplete`](/doc/api-reference/widgets/autocomplete/vue) widget reads from two indices: `instant_search_demo_query_suggestions` and `instant_search`.
    The first index widget is implied by the creation of the [`ais-instant-search`](/doc/api-reference/widgets/instantsearch/vue) widget.

    ```vue Vue icon=code theme={"system"}
    <template>
      <div>
        <ais-instant-search
          :search-client="searchClient"
          index-name="instant_search_demo_query_suggestions"
        >
          <ais-configure :hitsPerPage="5" />
          <ais-index index-name="instant_search" />
          <ais-autocomplete>
            <template v-slot="{ currentRefinement, indices, refine }">
              <vue-autosuggest
                :suggestions="indicesToSuggestions(indices)"
                @selected="onSelect"
                :input-props="{
                  style: 'width: 100%',
                  onInputChange: refine,
                  placeholder: 'Search here...',
                }"
              >
              <template v-slot="{ suggestion }">
                <ais-highlight
                  :hit="suggestion.item"
                  attribute="query"
                  v-if="suggestion.item.query"
                />
                <ais-highlight
                  :hit="suggestion.item"
                  attribute="name"
                  v-else
                />
                <strong v-if="suggestion.item.price">
                  $ {{ suggestion.item.price }}
                </strong>
                <img
                  :src="suggestion.item.image"
                  style="height: 50px;"
                  v-if="suggestion.item.image"
                />
              </template>
              </vue-autosuggest>
            </template>
          </ais-autocomplete>
        </ais-instant-search>
      </div>
    </template>

    <script>
    import { VueAutosuggest } from 'vue-autosuggest';

    export default {
      components: { VueAutosuggest },
      methods: {
        onSelect(selected) {
          if (selected) {
            const { query } = selected.item;
            this.query = query;
          }
        },
        indicesToSuggestions(indices) {
          return indices.map(({ hits }) => ({
            data: hits.map(hit => {
              return {
                ...hit,
                // this is for Vue Autosuggest
                name: hit.query,
              };
            }),
          }));
        },
      },
    };
    </script>
    ```
  </Step>
</Steps>

## Use the related categories in the autocomplete

A typical use of autocomplete is to display both relevant categories *and* suggestions.
Then when a user selects a suggestion, both the suggestion and the associated category are used to refine the search.
For this example, the relevant categories are stored on the suggestions <Records />.
You must update your render function to display the categories with the suggestions.
For simplicity and brevity of the code,
assume that all suggestions have categories,
but this isn't the case in the actual dataset.
Take a look at the complete example to see the actual implementation.

```vue Vue icon=code theme={"system"}
<template>
  <!-- ... -->
    <template v-slot="{ suggestion }">
      <span>
        <ais-highlight attribute="query" :hit="suggestion.item" />
        <span>
          <em>
            in
            <span v-if="suggestion.item.category">
              {{ suggestion.item.category.value }}
            </span>
            <span v-else> All categories </span>
          </em>
        </span>
      </span>
    </template>
  <!-- ... -->
</template>

<script>
export default {
  methods:
    indicesToSuggestions(indices) {
      return indices.map(({ hits }) => ({
        data: hits.map(hit => {
          // categories is an array, but you only want the first element
          // hit.instant_search is undefined if there are no matched categories
          const [category] =
            (hit.instant_search &&
              hit.instant_search.facets.exact_matches.categories) ||
            [];

          return {
            ...hit,
            category,
            name: hit.query,
          };
        }),
      }));
    },
  },
};
</script>
```

Now that you can display categories,
you can use them to refine the main search.
Use the [`ais-configure`](/doc/api-reference/widgets/configure/vue) widget with `disjunctiveFacets` and `disjunctiveFacetsRefinement`.
These two parameters are the same as internally used in a refinement list.

```vue Vue icon=code theme={"system"}
<template>
  <!-- ... -->
  <ais-instant-search
    :search-client="searchClient"
    index-name="instant_search"
  >
    <!-- optionally to display the selected category -->
    <ais-current-refinements />
    <ais-configure
      :query="query"
      :disjunctiveFacets="['categories']"
      :disjunctiveFacetsRefinements="disjunctiveFacetsRefinements"
    />
    <!-- ... -->
  </ais-instant-search>
</template>

<script>
export default {
  data() {
    return {
      query: '',
      disjunctiveFacetsRefinements: undefined,
    };
  },
  methods: {
    onSelect(selected) {
      if (selected) {
        const { query, category } = selected.item;
        this.query = query;
        this.disjunctiveFacetsRefinements = category && {
          categories: [category.value],
        };
      }
    },
  },
};
</script>
```

That's it. When a suggestion is selected, both the query *and* the category are applied to the main search.
