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

# Conditional display in InstantSearch.js

> Learn how to improve your InstantSearch.js app when there are no results, when there's no query, or when there are errors.

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

export const Filter = () => <Tooltip tip="A filter is a condition that limits which records Algolia returns. Filters often use one or more facet-value pairs, such as brand:Apple AND color:red. You can also filter by numeric values, dates, tags, booleans, or geographic constraints." cta="Filtering" href="/doc/guides/managing-results/refine-results/faceting">
    filter
  </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">JavaScript</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="true"><a className="afs-option is-current" href="/doc/guides/building-search-ui/going-further/conditional-display/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/going-further/conditional-display/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/going-further/conditional-display/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/going-further/conditional-display/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/going-further/conditional-display/android"><span className="afs-option-name">Android</span><span className="afs-option-lib">InstantSearch Android</span></a></li>
    </ul>
  </div>
</div>

This guide describes what to do when there are [no results](#handling-no-results), when there's [no query](#handling-empty-queries), or when there are [errors](#handling-errors). **Sometimes, though, users may not get any hits if their device [can't access the network or the network connection is slow](/doc/guides/building-search-ui/ui-and-ux-patterns/pagination/js#no-hits-or-is-the-search-still-in-progress).**

If you want to feature content in your search results based on a set of conditions, you can use Algolia Rules to:

* [Feature specific data from within your records](https://www.algolia.com/ecommerce-merchandising-playbook/merchandise-search-results-page/) to, for example, show promotional prices during a sales period
* [Display advertisements or promotional banners](/doc/guides/managing-results/rules/merchandising-and-promoting/how-to/add-banners).

<Info>
  To learn how to suppress InstantSearch's initial <SearchQuery />,
  see [Conditional requests](/doc/guides/building-search-ui/going-further/conditional-requests/js).
</Info>

## Handling no results

Since not all queries lead to results, it's essential to let users know when this happens by **providing hints on how to adjust the query.**

### Display a message

The easiest way to display a fallback message when a query doesn't return results is to use the [`templates.empty`](/doc/api-reference/widgets/hits/js#param-empty) option.

<Note>
  All examples in this guide assume you've included InstantSearch.js in your web page from a CDN. If, instead, you're using it with a package manager, adjust how you [import InstantSearch.js and its widgets](/doc/guides/building-search-ui/installation/js) for more information.
</Note>

```js JavaScript theme={"system"}
search.addWidgets([
  instantsearch.widgets.hits({
    container: 'hits',
    templates: {
      empty: ({ query }, { html }) =>
        html`<div>No results have been found for ${ query }.</div>`
    }
  })
]);
```

<Note>
  The preceding example also works with [`infiniteHits`](/doc/api-reference/widgets/infinite-hits/js).
</Note>

### Let users reset filters and facets

If users apply an overly specific <Filter /> configuration, they may not find any results.
You should account for this by letting them reset filters from the "no results" display so they can start another search.

Do this with the [`clearRefinements`](/doc/api-reference/widgets/clear-refinements/js) widget. However, you can't use it inside the `empty` template, so must use [routing](/doc/guides/building-search-ui/going-further/routing-urls/js) instead. First, activate the URL sync mechanism:

```js JavaScript theme={"system"}
const search = instantsearch({
  routing: true
});
```

Routing makes your InstantSearch app aware of changes in the URL. By removing URL parameters, you can influence search parameters and reset filters and facets.

```js JavaScript theme={"system"}
search.addWidgets([
  instantsearch.widgets.hits({
    container: 'hits',
    templates: {
      empty: ({ query }, { html }) =>
        html`<div>
          <p>No results have been found for ${query}}</p>
          <a role="button" href=".">Reset all filters</a>
        </div>`,
    },
  }),
]);
```

## Handling empty queries

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

### Using `transformItems`

Using `transformItems` to display no results when the query is empty:

```js JavaScript theme={"system"}
hits({
  transformItems(items, { results }) {
    if (results.query === '') return [];

    return items;
  },
  templates: {
    empty(results, { html }) {
      if (results.query === '') return null;

      return html`No results found for "${results.query}"`;
    },
  }
});
```

### Using a connector

The following example uses the [`connectHits`](/doc/api-reference/widgets/hits/js#customize-the-ui-with-connecthits) connector.

```js JavaScript theme={"system"}
const customHits = instantsearch.connectors.connectHits(
  (renderOptions, isFirstRender) => {
    const { results, widgetParams } = renderOptions;
    const { container } = widgetParams;

    container.innerHTML =
      results && results.query
        ? `<div>Searching for query "${results.query}".</div>`
        : `<div>No query</div>`;
  }
);

search.addWidgets([
  customHits({
    container: document.querySelector('#hits')
  })
]);
```

## Handling errors

If an error occurs, you can display a specific piece of content to help users return to the standard state.

### Making an error-handling widget

You can build a custom widget to handle errors. If you want to learn more about custom widgets, [check out the guide](/doc/guides/building-search-ui/widgets/create-your-own-widgets/js).

```js JavaScript theme={"system"}
search.addWidgets([
  {
    $$type: 'error-display',
    render({ status, error }) {
      if (status === 'error' && error) {
        console.error('Error', error);
      }
    }
  }
]);
```

You can improve this custom widget by writing a more meaningful error message, adapting it to your UI, figuring out if users are online, and logging the error in your monitoring system.
