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

# Autocomplete

> Learn how to build an autocomplete search experience with React InstantSearch.

export const customLabel_0 = undefined

export const FlavorSwitcher = ({current, baseHref = "", options = [], label = "InstantSearch framework"}) => {
  if (options.length === 0) {
    return <div className="not-prose" role="alert" style={{
      margin: "0.25rem 0 1.5rem",
      padding: "0.75rem",
      border: "1px solid #f59e0b",
      borderRadius: "0.625rem",
      color: "inherit",
      fontSize: "0.875rem"
    }}>
        FlavorSwitcher requires at least one option.
      </div>;
  }
  const selected = options.find(option => option.value === current) ?? options[0];
  return <div className="not-prose mint-flavor-switcher">
      <style>{`
        .mint-flavor-switcher {
          --mfs-bg: #ffffff;
          --mfs-bg-hover: #f4f4f5;
          --mfs-bg-current: #eef2ff;
          --mfs-border: #d4d4d8;
          --mfs-fg: #18181b;
          --mfs-muted: #71717a;
          --mfs-accent: #4f46e5;
          position: relative;
          width: min(100%, 19rem);
          margin: 0.25rem 0 1.5rem;
          color: var(--mfs-fg);
          font-size: 0.875rem;
          line-height: 1.25rem;
        }

        .dark .mint-flavor-switcher {
          --mfs-bg: #18181b;
          --mfs-bg-hover: #27272a;
          --mfs-bg-current: #272747;
          --mfs-border: #3f3f46;
          --mfs-fg: #fafafa;
          --mfs-muted: #a1a1aa;
          --mfs-accent: #a5b4fc;
        }

        .mint-flavor-switcher details {
          position: relative;
        }

        .mint-flavor-switcher summary {
          display: flex;
          min-height: 2.75rem;
          box-sizing: border-box;
          align-items: center;
          justify-content: space-between;
          gap: 0.75rem;
          padding: 0.625rem 0.75rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          color: var(--mfs-fg);
          cursor: pointer;
          font-weight: 600;
          list-style: none;
          transition: border-color 150ms ease, box-shadow 150ms ease;
        }

        .mint-flavor-switcher summary::-webkit-details-marker {
          display: none;
        }

        .mint-flavor-switcher summary:hover {
          border-color: var(--mfs-accent);
        }

        .mint-flavor-switcher summary:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: 2px;
        }

        .mint-flavor-switcher__label {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        .mint-flavor-switcher__chevron {
          flex: none;
          transition: transform 150ms ease;
        }

        .mint-flavor-switcher details[open] .mint-flavor-switcher__chevron {
          transform: rotate(180deg);
        }

        .mint-flavor-switcher__menu {
          position: absolute;
          z-index: 50;
          top: calc(100% + 0.375rem);
          left: 0;
          width: 100%;
          box-sizing: border-box;
          margin: 0;
          padding: 0.375rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          box-shadow: 0 12px 30px rgb(0 0 0 / 16%);
          list-style: none;
        }

        .mint-flavor-switcher__menu li {
          margin: 0;
          padding: 0;
        }

        .mint-flavor-switcher__option {
          display: grid;
          gap: 0.125rem;
          padding: 0.625rem 0.75rem;
          border-radius: 0.4rem;
          color: var(--mfs-fg);
          text-decoration: none;
        }

        .mint-flavor-switcher__option:hover {
          background: var(--mfs-bg-hover);
        }

        .mint-flavor-switcher__option:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: -2px;
        }

        .mint-flavor-switcher__option[aria-current="page"] {
          background: var(--mfs-bg-current);
          color: var(--mfs-accent);
        }

        .mint-flavor-switcher__name {
          font-weight: 600;
        }

        .mint-flavor-switcher__description {
          color: var(--mfs-muted);
          font-size: 0.8125rem;
        }

        @media (prefers-reduced-motion: reduce) {
          .mint-flavor-switcher summary,
          .mint-flavor-switcher__chevron {
            transition: none;
          }
        }
      `}</style>

      <details>
        <summary aria-label={`${label}: ${selected.label}`}>
          <span className="mint-flavor-switcher__label">{selected.label}</span>
          <svg className="mint-flavor-switcher__chevron" width="18" height="18" 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>
        </summary>

        <ul className="mint-flavor-switcher__menu" aria-label={label}>
          {options.map(option => {
    const isCurrent = option.value === selected.value;
    const href = option.href ?? `${baseHref.replace(/\/$/, "")}/${encodeURIComponent(option.value)}`;
    return <li key={option.value}>
                <a className="mint-flavor-switcher__option" href={href} aria-current={isCurrent ? "page" : undefined}>
                  <span className="mint-flavor-switcher__name">
                    {option.label}
                  </span>
                  {option.description ? <span className="mint-flavor-switcher__description">
                      {option.description}
                    </span> : null}
                </a>
              </li>;
  })}
        </ul>
      </details>
    </div>;
};

<div className="mint-flavor-switcher-slot not-prose">
  <FlavorSwitcher
    current="react"
    baseHref="/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete"
    options={[
{ value: "js", label: "JavaScript", description: "InstantSearch.js" },
{ value: "react", label: "React", description: "React InstantSearch" },
{ value: "vue", label: "Vue", description: "Vue InstantSearch" },
{ value: "ios", label: "iOS", description: "InstantSearch iOS" },
{ value: "android", label: "Android", description: "InstantSearch Android" },
]}
  />
</div>

<Note>
  This is the **React InstantSearch v7** documentation.
  If you're upgrading from v6, see the [upgrade guide](/doc/guides/building-search-ui/upgrade-guides/react/#migrate-from-react-instantsearch-v6-to-react-instantsearch-v7).
  If you were using React InstantSearch Hooks,
  this v7 documentation applies—just check for [necessary changes](/doc/guides/building-search-ui/upgrade-guides/react/#migrate-from-react-instantsearch-hooks-to-react-instantsearch-v7).
  To continue using v6, you can find the [archived documentation](https://algolia.com/old-docs/deprecated/instantsearch/react/v6/api-reference/instantsearch/).
</Note>

**Autocomplete is a ubiquitous part of most search experiences.**
Search providers like Google, ecommerce sites like Amazon,
and messaging apps like Slack all offer autocomplete experiences on mobile and desktop.

Algolia provides a full-featured solution to build autocomplete experiences with React InstantSearch. The [`<Autocomplete>`](/doc/api-reference/widgets/autocomplete/react) widget lets you build an accessible, as-you-type autocomplete user interface that you can integrate anywhere on your site or app.

<Columns>
  <Card title="Open CodeSandbox" icon="box" href="https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/query-suggestions">
    Run and edit the Autocomplete example in CodeSandbox.
  </Card>

  <Card title="Explore source code" icon="github" href="https://github.com/algolia/instantsearch/tree/master/examples/react/query-suggestions">
    Browse the source for the Autocomplete example on GitHub.
  </Card>
</Columns>

A common pattern in search is to implement a search box with an autocomplete as a first step of the search experience. **Adding an autocomplete to a search page lets you enhance the search experience and create a richer, more contextual search.**

You can use the [`<Autocomplete>`](/doc/api-reference/widgets/autocomplete/react) widget in an existing or a new React InstantSearch implementation to create this kind of experience.

<Callout icon="flask-conical" color="#14b8a6">
  This widget is **{customLabel_0 || "experimental"}** and is subject to change in minor versions.
</Callout>

## Install React InstantSearch

The `<Autocomplete>` widget is part of React InstantSearch.
Install React InstantSearch and the Algolia API client from the [npm](https://www.npmjs.com/) registry:

<CodeGroup>
  ```sh npm theme={"system"}
  npm install algoliasearch react-instantsearch instantsearch.css
  ```

  ```sh yarn theme={"system"}
  yarn add algoliasearch react-instantsearch instantsearch.css
  ```
</CodeGroup>

Import a theme to style the widget out of the box:

```jsx JavaScript icon=code theme={"system"}
import "instantsearch.css/themes/satellite.css";
```

## Add the widget to InstantSearch

Render the `<EXPERIMENTAL_Autocomplete>` component inside an [`<InstantSearch>`](/doc/api-reference/widgets/instantsearch/react) provider:

```jsx JavaScript icon=code theme={"system"}
import React from "react";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { InstantSearch, EXPERIMENTAL_Autocomplete } from "react-instantsearch";

import "instantsearch.css/themes/satellite.css";

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

function App() {
  return (
    <InstantSearch indexName="instant_search" searchClient={searchClient}>
      <EXPERIMENTAL_Autocomplete placeholder="Search for products" />
    </InstantSearch>
  );
}
```

The widget is added to InstantSearch but it doesn't show results until you configure the indices to query.

## Display results from an index

Use the [`indices`](/doc/api-reference/widgets/autocomplete/react/#param-indices) prop to define which indices to query and how to display their results.
In React, you provide React components with `headerComponent` and `itemComponent`, and a `getURL` function to navigate when a user selects an item:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  placeholder="Search for products"
  indices={[
    {
      indexName: "instant_search",
      getURL: (item) => `/products/${item.objectID}`,
      searchParameters: { hitsPerPage: 5 },
      headerComponent: ({ items }) => <div>Products ({items.length})</div>,
      itemComponent: ({ item, onSelect }) => (
        <button type="button" onClick={onSelect}>
          {item.name}
        </button>
      ),
    },
  ]}
/>
```

You can query several indices at once by adding more objects to the `indices` prop.
To learn more, see [Including multiple result types](/doc/ui-libraries/autocomplete/guides/including-multiple-result-types).

## Customize result templates

Each index renders with `headerComponent`, `itemComponent`, and `noResultsComponent`, and the widget accepts a top-level `panelComponent` for the overall layout.
The [Display results from an index](#display-results-from-an-index) section covers `headerComponent` and `itemComponent`.

### Highlight the matched query

Use the `<Highlight>` component from `react-instantsearch` in an item component to emphasize the part of an attribute matching the user's query:

```jsx JavaScript icon=code theme={"system"}
import { Highlight } from "react-instantsearch";

<EXPERIMENTAL_Autocomplete
  indices={[
    {
      indexName: "instant_search",
      itemComponent: ({ item }) => <Highlight hit={item} attribute="name" />,
    },
  ]}
/>;
```

Use `<Snippet>` to highlight within a longer, truncated attribute, and `<ReverseHighlight>` to emphasize the text that doesn't match.
This is a common style for Query Suggestions.

### Show an empty state

The `noResultsComponent` renders when an index returns nothing.
If any index defines it, the panel stays open even when every index is empty, so you can show a helpful message:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  indices={[
    {
      indexName: "instant_search",
      itemComponent: ({ item }) => <div>{item.name}</div>,
      noResultsComponent: () => <div>No products found.</div>,
    },
  ]}
/>
```

### Customize the panel layout

The top-level `panelComponent` controls the layout of the whole panel, including the order and grouping of recent searches, query suggestions, and each index.
It receives an `elements` object whose keys are `recent`, `suggestions`, and each index's `indexName`, so you can arrange sections into rows or columns—for example, suggestions on the left and results on the right:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  panelComponent={({ elements }) => (
    <div className="aa-grid">
      <div className="aa-column">{elements.suggestions}</div>
      <div className="aa-column">{elements["instant_search"]}</div>
    </div>
  )}
  indices={[
    {
      indexName: "instant_search",
      itemComponent: ({ item }) => <div>{item.name}</div>,
    },
  ]}
/>
```

The component only sets the markup. Style the columns with your own CSS:

```css CSS icon=code theme={"system"}
.aa-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 1rem;
}
```

## Filter results

To narrow what an index returns, set Algolia [search parameters](/doc/api-reference/search-api-parameters) on that index with `searchParameters`.
You can apply [`filters`](/doc/api-reference/api-parameters/filters), [`facetFilters`](/doc/api-reference/api-parameters/facetFilters), [`numericFilters`](/doc/api-reference/api-parameters/numericFilters), and other parameters per index:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  indices={[
    {
      indexName: "instant_search",
      itemComponent: ({ item }) => <div>{item.name}</div>,
      searchParameters: {
        hitsPerPage: 5,
        filters: "categories:Phones",
        facetFilters: [["brand:Apple", "brand:Samsung"]],
      },
    },
  ]}
/>
```

The widget applies these parameters to every query for that index.
For an interactive filter UI inside the autocomplete—such as selectable tags or facet values that users add and remove—use the standalone [Autocomplete](/doc/ui-libraries/autocomplete/guides/filtering-results) library, which provides the tags plugin and facet sources.

## Reshape and deduplicate results

Use the `transformItems` prop to adjust results before they're displayed—for example, to remove duplicates across indices or limit the number of items each index shows.
The function receives an array with one entry per index, each shaped as `{ indexName, indexId, hits, results }`, and must return the same shape:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  indices={[
    {
      indexName: "instant_search",
      itemComponent: ({ item }) => <div>{item.name}</div>,
    },
    {
      indexName: "instant_search_demo_query_suggestions",
      itemComponent: ({ item }) => <div>{item.query}</div>,
    },
  ]}
  transformItems={(indices) => {
    const seen = new Set();

    return indices.map((index) => ({
      ...index,
      hits: index.hits
        .filter((hit) => {
          if (seen.has(hit.objectID)) {
            return false;
          }
          seen.add(hit.objectID);
          return true;
        })
        .slice(0, 5),
    }));
  }}
/>
```

Unlike the standalone library's [reshape](/doc/ui-libraries/autocomplete/guides/reshaping-sources) API, the widget doesn't group or sort sources for you—deduplication and per-index limits are manual, as shown above.

## Add Query Suggestions and recent searches

The widget can display query suggestions from a [Query Suggestions index](/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/react) and recent searches stored in the browser's local storage.
Enable them with the [`showQuerySuggestions`](/doc/api-reference/widgets/autocomplete/react/#param-showquerysuggestions) and [`showRecent`](/doc/api-reference/widgets/autocomplete/react/#param-showrecent) props:

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  placeholder="Search for products"
  showRecent
  showQuerySuggestions={{
    indexName: "instant_search_demo_query_suggestions",
    getURL: (item) => `/search?q=${item.query}`,
  }}
  indices={[
    {
      indexName: "instant_search",
      // ...
    },
  ]}
/>
```

To template suggestions and recent searches, set a custom storage key, or refine your main index when a user selects a suggestion, see [Build a Query Suggestions UI](/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete/query-suggestions/react).

## Send click and conversion events

To send [click and conversion events](/doc/guides/sending-events/getting-started) when users interact with the autocomplete,
enable the `insights` prop on the [`<InstantSearch>`](/doc/api-reference/widgets/instantsearch/react) provider:

```jsx JavaScript icon=code theme={"system"}
<InstantSearch indexName="instant_search" searchClient={searchClient} insights>
  {/* ... */}
</InstantSearch>
```

The widget then sends view and click events automatically when users see and select results.

Conversion events, like `add-to-cart`, usually happen after the user leaves the autocomplete, on the destination page.
Send those where the conversion occurs with the [Insights client](/doc/guides/sending-events/getting-started).
The autocomplete item component doesn't expose a `sendEvent` function.

## Support keyboard navigation

The widget renders an accessible combobox, so users can operate it entirely from the keyboard—no extra configuration:

* **Up and Down arrows** move through the items. The highlight wraps around at the ends of the list.
* **Enter** opens the highlighted item, or submits the typed query when nothing is highlighted.
* **Escape** closes the panel, then clears the highlight.
* **Tab** closes the panel and moves focus to the next element.

What happens on **Enter** depends on how you handle navigation:

* If the highlighted item's index defines [`getURL`](#display-results-from-an-index), the browser opens that URL.
* Otherwise, when you set `getSearchPageURL`, submitting the query sends the user to your search results page.
* To use client-side routing instead of a full page load, provide an `onSelect` function and navigate yourself.

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  // On Enter with no highlighted item, open the search results page.
  getSearchPageURL={({ query }) => `/search?q=${query}`}
  indices={[
    {
      indexName: "instant_search",
      // On Enter or click with a highlighted item, open its URL.
      getURL: (item) => `/products/${item.objectID}`,
      itemComponent: ({ item }) => <div>{item.name}</div>,
    },
  ]}
/>
```

The widget also sets the matching ARIA roles (`combobox`, `aria-expanded`, `aria-activedescendant`), so screen readers announce the active item as users move through the list.

## Enable detached (mobile) mode

On small screens, the widget can switch to a full-screen overlay.
Use the [`detachedMediaQuery`](/doc/api-reference/widgets/autocomplete/react/#param-detachedmediaquery) prop to control when this happens.
By default, detached mode activates at `(max-width: 680px)`.

```jsx JavaScript icon=code theme={"system"}
<EXPERIMENTAL_Autocomplete
  detachedMediaQuery="(max-width: 1024px)"
  placeholder="Search for products"
/>
```

To turn off detached mode, set `detachedMediaQuery` to an empty string.

## Explore advanced examples

* [Federated two-column autocomplete](/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete/examples/federated/react): a layout that combines recent searches, Query Suggestions, product previews, a quick-access panel, and category suggestions.
* [Rich text box with mentions](/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete/examples/mentions/react): a headless "@" mentions text box, built with the [`useAutocomplete`](/doc/api-reference/widgets/autocomplete/react) hook, that reproduces the X compose experience.

## See also

* [`<Autocomplete>`](/doc/api-reference/widgets/autocomplete/react) widget reference for the full list of props.
* [Build a Query Suggestions UI](/doc/guides/building-search-ui/ui-and-ux-patterns/autocomplete/query-suggestions/react).
