Guides / Building Search UI / UI & UX patterns

Overview

It might happen that you want to search across multiple indices at the same time. React InstantSearch has a built-in solution for this use case, the Index component. The widgets scoped under this Index component will target the provided index. The widgets that are not scoped under an Index are “shared” across all the indices. This widget is really useful whenever you want to:

  • display hits from different indices
  • share a single SearchBox
  • build an autocomplete menu targeting different indices

In this guide we will learn how to share a single SearchBox to display multiple hits from different indices. We will also take a look at how to create an autocomplete that targets multiple indices. The source code of both examples can be found on GitHub.

Search in multiple indices

For this first use case we share a single SearchBox to search into multiple indices. Both Hits widgets are scoped under an Index component. It means that they are restricted to display results from this particular index. In the first case the instant_search and in the second case instant_search_price_desc.

If you want to perform a multi index search on the same index (for example, to trigger several searches on the same index with different parameters), make sure to define the indexId property on your Index widgets.

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
import algoliasearch from 'algoliasearch/lite';
import {
  InstantSearch,
  Index,
  SearchBox,
  Hits
} from 'react-instantsearch-dom';

const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
);

const App = () => (
  <InstantSearch indexName="instant_search" searchClient={searchClient}>
    <SearchBox />

    <Index indexName="instant_search">
      <h2>index: instant_search</h2>
      <Hits />
    </Index>

    <Index indexName="instant_search_price_desc">
      <h2>index: instant_search_price_desc</h2>
      <Hits />
    </Index>
  </InstantSearch>
);

Not only the Hits widget can be scoped under an Index component, but every widget can be used. In the following example we want to display a different number of results in our two sets of results. instant_search index will display 8 results and instant_search_price_desc 16 results. To restrict the number of results per page we use the Configure widget. Each widget will be scoped under the index that we want to target.

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
import algoliasearch from 'algoliasearch/lite';
import {
  InstantSearch,
  Index,
  Configure,
  SearchBox,
  Hits
} from 'react-instantsearch-dom';

const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
);

const App = () => (
  <InstantSearch indexName="instant_search" searchClient={searchClient}>
    <SearchBox />

    <Index indexName="instant_search">
      <h2>index: instant_search</h2>
      <Configure hitsPerPage={8} />
      <Hits />
    </Index>

    <Index indexName="instant_search_price_desc">
      <h2>index: instant_search_price_desc</h2>
      <Configure hitsPerPage={16} />
      <Hits />
    </Index>
  </InstantSearch>
);

You can find the complete example on GitHub.

Autocomplete

For this second use case, we are building an autocomplete that searches into multiple indices. The focus of this guide is on search into multiple indices. We do not cover the autocomplete implementation in depth because it has its own guide. The autocomplete is built with React Autosuggest and the Autocomplete connector. Note that the shape of the hits argument changes depending on whether it’s used in a single- or multi-index context. In a single index context the value is an array of hits. But in a multi-index context the value is an array of objects that contain two properties index and hits.

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
59
60
61
62
63
64
65
66
import { Highlight, connectAutoComplete } from 'react-instantsearch-dom';
import AutoSuggest from 'react-autosuggest';

class AutoComplete extends Component {
  state = {
    value: this.props.currentRefinement,
  };

  onChange = (event, { newValue }) => {
    this.setState({
      value: newValue,
    });
  };

  onSuggestionsFetchRequested = ({ value }) => {
    this.props.refine(value);
  };

  onSuggestionsClearRequested = () => {
    this.props.refine();
  };

  getSuggestionValue(hit) {
    return hit.name;
  }

  renderSuggestion(hit) {
    return <Highlight attribute="name" hit={hit} tagName="mark" />;
  }

  renderSectionTitle(section) {
    return section.index;
  }

  getSectionSuggestions(section) {
    return section.hits;
  }

  render() {
    const { hits, onSuggestionSelected } = this.props;
    const { value } = this.state;

    const inputProps = {
      placeholder: 'Search for a product...',
      onChange: this.onChange,
      value,
    };

    return (
      <AutoSuggest
        suggestions={hits}
        multiSection={true}
        onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
        onSuggestionsClearRequested={this.onSuggestionsClearRequested}
        onSuggestionSelected={onSuggestionSelected}
        getSuggestionValue={this.getSuggestionValue}
        renderSuggestion={this.renderSuggestion}
        inputProps={inputProps}
        renderSectionTitle={this.renderSectionTitle}
        getSectionSuggestions={this.getSectionSuggestions}
      />
    );
  }
}

export default connectAutoComplete(AutoComplete);

Once we have our autocomplete component we can use with it in our multi-index application. The component will have access to both indices. It will also leverage the Configure to reduce the number of hits.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, Index, Configure } from "react-instantsearch-dom";
import AutoComplete from "./AutoComplete";

const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
);

const App = () => (
  <InstantSearch indexName="instant_search" searchClient={searchClient}>
    <Configure hitsPerPage={3} />
    <AutoComplete />
    <Index indexName="instant_search" />
    <Index indexName="instant_search_price_desc" />
  </InstantSearch>
);

You can find the complete example on GitHub.

Did you find this page helpful?