UI libraries / Autocomplete / Integrations

Using Autocomplete with React

This guide shows how to create a React Autocomplete component. It uses the useRef and useEffect Hooks to create and mount the component. It doesn’t define specific sources. Rather, you can pass sources and other options as props.

Before you begin

The guide assumes you’re familiar with the basic Autocomplete configuration options and have an existing React (v16.8+) app to which you want to add an Autocomplete menu.

Creating the component

Add the following starter code for creating a React component. This component uses the useRef Hook to create a mutable ref object, containerRef, for mounting the autocomplete.

All that you need to render is a div with the containerRef as the ref.

1
2
3
4
5
6
7
8
9
10
11
12
13
import React, { Fragment, useEffect, useRef } from 'react';

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

  useEffect(() => {
    if (!containerRef.current) {
      return undefined;
    }
  }, [props]);

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

Mounting the autocomplete

Now that you have access to the DOM through the containerRef object, you can create and mount the Autocomplete instance. Upon instantiation, you can include any desired Autocomplete options and rely on props to pass any options you want to remain configurable.

The following examples specify where to mount your Autocomplete component with the container option, but lets all other options get configured through props.

The default Autocomplete implementation uses Preact APIs to create and render elements, so you need to replace them with React APIs to properly render the views. Depending on your React version, the implementation slightly differs. In both cases, clean up the effect by returning a function that destroys the Autocomplete instance.

With React 18

With React 18, you should only pass React createElement and Fragment to the renderer option. To silence the warning from Autocomplete, you can pass an empty function to renderer.render.

Instead, you should use the render option to create a Root object with the React createRoot function, then use this object to render.

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
import { autocomplete } from '@algolia/autocomplete-js';
import React, { createElement, Fragment, useEffect, useRef } from 'react';
import { createRoot } from 'react-dom/client';

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

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

    const search = autocomplete({
      container: containerRef.current,
      renderer: { createElement, Fragment, render: () => {} },
      render({ children }, root) {
        if (!panelRootRef.current || rootRef.current !== root) {
          rootRef.current = root;

          panelRootRef.current?.unmount();
          panelRootRef.current = createRoot(root);
        }

        panelRootRef.current.render(children);
      },
      ...props,
    });

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

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

With React 16.8 or 17

With React 16.8 or 17, you need to import createElement, Fragment, and render from React and provide them to the Autocomplete renderer option.

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

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

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

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

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

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

Using the component

Now that you’ve created an <Autocomplete /> component, you can use it in your React application.

The usage below sets openOnFocus and sources through props. This example uses an Algolia index as a source, but you could use anything else you want, including plugins. For more information about using Algolia as a source, see Getting started.

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
import React, { createElement } from 'react';
import { getAlgoliaResults } from '@algolia/autocomplete-js';
import algoliasearch from 'algoliasearch';
import { Autocomplete } from './components/Autocomplete';
import { ProductItem } from './components/ProductItem';

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

function App() {
  return (
    <div className="app-container">
      <h1>React Application</h1>
      <Autocomplete
        openOnFocus={true}
        getSources={({ query }) => [
          {
            sourceId: 'products',
            getItems() {
              return getAlgoliaResults({
                searchClient,
                queries: [
                  {
                    indexName: 'instant_search',
                    query,
                  },
                ],
              });
            },
            templates: {
              item({ item, components }) {
                return <ProductItem hit={item} components={components} />;
              },
            },
          },
        ]}
      />
    </div>
  );
}

export default App;

Creating templates

The example preceding passes <ProductItem />, another React component, for the item template.

1
2
3
4
5
6
7
8
9
10
11
12
13
import React, { createElement } from 'react';

export function ProductItem({ hit, components }) {
  return (
    <a href={hit.url} className="aa-ItemLink">
      <div className="aa-ItemContent">
        <div className="aa-ItemTitle">
          <components.Highlight hit={hit} attribute="name" />
        </div>
      </div>
    </a>
  );
}

Further UI customization

If you want to build a custom UI that differs from the autocomplete-js output, check out the guide on creating a custom renderer. This guide outlines how to create a custom React renderer specifically, but the underlying principles are the same for any other frontend framework.

Did you find this page helpful?