Guides / Building Search UI / Going further / Conditional display

Conditional Display in React InstantSearch Hooks

Handling no results

Not all queries lead to results, and it’s important to let users know when this happens. This gives you an opportunity to provide hints on how to adjust the query. This way, you can ensure users don’t leave your website or search using an external search engine.

Display a message

The easiest way to display a fallback message when a query doesn’t return results is to use the useInstantSearch() Hook to create a wrapper component.

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
function App(props) {
  return (
    <InstantSearch {...props}>
      <SearchBox />
      <NoResultsBoundary fallback={<NoResults />}>
        <Hits />
      </NoResultsBoundary>
    </InstantSearch>
  );
}

function NoResultsBoundary({ children, fallback }) {
  const { results } = useInstantSearch();

  // The `__isArtificial` flag makes sure to not display the No Results message
  // when no hits have been returned yet.
  if (!results.__isArtificial && results.nbHits === 0) {
    return (
      <>
        {fallback}
        <div hidden>{children}</div>
      </>
    );
  }

  return children;
}

function NoResults() {
  const { indexUiState } = useInstantSearch();

  return (
    <div>
      <p>
        No results for <q>{indexUiState.query}</q>.
      </p>
    </div>
  );
}

Note that the above example lets you pass anything to display results, including <InfiniteHits> or a custom component that uses the useHits() Hook.

Let the user clear all filters

Users make mistakes, which can cause them to not find any results. You can account for this by providing a way to clear filters right from the “no results” state, so they can start over.

You can achieve this with the <ClearRefinements> widget.

1
2
3
4
5
6
7
8
9
10
11
12
function NoResults() {
  const { indexUiState } = useInstantSearch();

  return (
    <div>
      <p>
        No results for <q>{indexUiState.query}</q>.
      </p>
      <ClearRefinements excludedAttributes={[]} />
    </div>
  );
}

Handling the empty query

By default, React InstantSearch Hooks always shows you results, even when the query is empty. Depending on your use case and the way you want to build your UI, you may want to only show results when there’s a query.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function App(props) {
  return (
    <InstantSearch {...props}>
      <SearchBox />
      <EmptyQueryBoundary fallback={null}>
        <Hits />
      </EmptyQueryBoundary>
    </InstantSearch>
  );
}

function EmptyQueryBoundary({ children, fallback }) {
  const { indexUiState } = useInstantSearch();

  if (!indexUiState.query) {
    return fallback;
  }

  return children;
}

Handling errors

When an error occurs, you might want to display a specific piece of content to help the user go back to a normal 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
57
58
import React, { useEffect, useState } from 'react';
import * as Toast from '@radix-ui/react-toast';
import { useInstantSearch } from 'react-instantsearch-hooks-web';

function SearchErrorToast() {
  const { use } = useInstantSearch();
  const [error, setError] = useState(null);

  useEffect(() => {
    const middleware = ({ instantSearchInstance }) => {
      function handleError(searchError) {
        setError(searchError);
      }

      return {
        subscribe() {
          instantSearchInstance.addListener('error', handleError);
        },
        unsubscribe() {
          instantSearchInstance.removeListener('error', handleError);
        },
      };
    };

    return use(middleware);
  }, [use]);

  if (!error) {
    return null;
  }

  return (
    <Toast.Provider>
      <Toast.Root
        onOpenChange={(isOpen) => {
          if (!isOpen) {
            setError(null);
          }
        }}
      >
        <Toast.Title>{error.name}</Toast.Title>
        <Toast.Description>{error.message}</Toast.Description>
      </Toast.Root>

      <Toast.Viewport />
    </Toast.Provider>
  );
}

function App(props) {
  return (
    <InstantSearch {...props}>
      <SearchErrorToast />
      <SearchBox />
      <Hits />
    </InstantSearch>
  );
}
Did you find this page helpful?