Guides / Building Search UI / UI & UX patterns / Query Suggestions

Build a Query Suggestions UI with React InstantSearch

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.

To help users with their search, Algolia provides Query Suggestions. This feature creates an index with the best queries generated by users. You can then use this index to propose suggestions to your users as they’re typing into an Autocomplete input.

Once you’ve configured the generation of the Query Suggestions index, you need to query this index as well. You can use the autocomplete-plugin-query-suggestions package to integrate them into the autocomplete menu.

This guide shows how to use Autocomplete to display a list of suggestions and their associated categories. Once users select a suggestion, you will apply the query and the category using React InstantSearch.

Refine your results with the suggestions

The first step is to set up an autocomplete component with Autocomplete. You can find more information in the guide on Using Autocomplete with React.

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
import React, { useEffect, useRef, createElement, Fragment } from 'react';
import { render } from 'react-dom';

import { autocomplete } from '@algolia/autocomplete-js';

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

export function Autocomplete(props) {
  const containerRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) {
      return;
    }

    const search = autocomplete({
      ...props,
      container: containerRef.current,
      renderer: { createElement, Fragment, render },
    });

    return () => search.destroy();
  }, [props]);

  return <div ref={containerRef} />;
}

Now that you have your Autocomplete component, you can create the multi-index search experience. To start, create a component that acts as the interface between Autocomplete and React InstantSearch.

Inside, the autocomplete-plugin-query-suggestions package provides the createQuerySuggestionsPlugin function for creating a Query Suggestions plugin out-of-the-box. It requires the same Algolia search client used for your React InstantSearch app and an indexName. The indexName is the name of your Query Suggestions index.

To apply the suggestion, you can implement the useInstantSearch() Hook. You also need to mount a <SearchBox> widget or use its Hook to have React InstantSearch handle its state.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import React, { useCallback, useMemo } from 'react';

import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';

import {
  useInstantSearch,
  useSearchBox,
} from 'react-instantsearch';

import { Autocomplete } from './Autocomplete';
import { searchClient } from './searchClient';

export function SearchBoxWithSuggestions() {
  const { setIndexUiState } = useInstantSearch();
  const { query } = useSearchBox();

  const plugins = useMemo(() => {
    const querySuggestionsPlugin = createQuerySuggestionsPlugin({
      indexName: 'instant_search_demo_query_suggestions',
      searchClient,
      transformSource({ source }) {
        return {
          ...source,
          onSelect({ item }) {
            setIndexUiState((indexUiState) => ({
              ...indexUiState,
              query: item.query,
            }));
          },
        };
      },
    });

    return [querySuggestionsPlugin];
  }, []);

  const initialState = useMemo(() => ({ query }), [query]);

  const onReset = useCallback(
    () =>
      setIndexUiState((indexUiState) => ({
        ...indexUiState,
        query: '',
      })),
    []
  );

  return (
    <Autocomplete
      placeholder="Search for products…"
      plugins={plugins}
      initialState={initialState}
      onReset={onReset}
    />
  );
}

That’s it. You have set up your autocomplete multi-index search experience, and users can now select a suggestion and use it to search the main index.

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...

const querySuggestionsPlugin = createQuerySuggestionsPlugin({
  // ...
  categoryAttributes: [
    'instant_search',
    'facets',
    'exact_matches',
    'categories',
  ],
});

// ...
}

Now that you can display categories, you can use them to refine the main search. Mount a <Menu> widget or use its Hook, then update the UI state with setIndexUiState.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// ...

import {
  useInstantSearch,
  useMenu,
  useSearchBox,
} from 'react-instantsearch';

export function SearchBoxWithSuggestions() {
  const { setIndexUiState } = useInstantSearch();
  const { query } = useSearchBox();
  useMenu({ attribute: 'categories' });

  const plugins = useMemo(() => {
    const querySuggestionsPlugin = createQuerySuggestionsPlugin({
      indexName: 'instant_search_demo_query_suggestions',
      searchClient,
      categoryAttributes: ['instant_search', 'facets', 'exact_matches', 'categories'],
      transformSource({ source }) {
        return {
          ...source,
          onSelect({ item }) {
            setIndexUiState((indexUiState) => ({
              ...indexUiState,
              query: item.query,
              menu: {
                categories: item.__autocomplete_qsCategory || '',
              },
            }));
          },
        };
      },
    });

    return [querySuggestionsPlugin];
  }, []);

  const initialState = useMemo(() => ({ query }), [query]);

  const onReset = useCallback(
    () =>
      setIndexUiState((indexUiState) => ({
        ...indexUiState,
        query: '',
        menu: { categories: '' },
      })),
    []
  );

  return (
    <Autocomplete
      placeholder="Search for products…"
      plugins={plugins}
      initialState={initialState}
      onReset={onReset}
    />
  );
}

That’s it. Now when a suggestion’s category is selected, both the query and the category are applied to the main search.

If you are using React Native, you can achieve the same result with ease. Check out this source code example.

Did you find this page helpful?