UI libraries / Autocomplete / Guides

By default, Autocomplete offers as-you-type search and processes sources for each keystroke: a real-time experience with instant feedback. However, there are situations when as-you-type might not be desirable or even possible.

Debouncing helps prevent too many requests by waiting for a pause in activity. Debouncing can help in these cases:

  • Avoid sending too many requests in a short period. When using rate-limited services like the GitHub API, sending frequent requests can cause errors.
  • Accommodate users who prefer reduced UI motion. As-you-type search results can change the UI rapidly.
  • Anticipate typing speed. By carefully selecting an appropriate debounce delay for your audience, you can significantly reduce the number of search requests while maintaining a good user experience.

Write a debouncing function

To tell Autocomplete to “wait” for a set time after typing stops before returning results, write a debouncing function that returns a promise. When the timeout elapses, the promise for the passed items is resolved.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { autocomplete } from '@algolia/autocomplete-js';

function debouncePromise(fn, time) {
  let timer = undefined;

  return function debounced(...args) {
    if (timer) {
      clearTimeout(timer); // Clear the timeout first if it's already defined.
    }

    return new Promise((resolve) => {
      timer = setTimeout(() => resolve(fn(...args)), time);
    });
  };
}

The debouncePromise function lets you create a wrapper around any asynchronous function and delay it for a specified time: 200 ms in the example.

1
2
const DEBOUNCE_MS = 200;
const debounced = debouncePromise((items) => Promise.resolve(items), DEBOUNCE_MS);

Select a debounce delay

The optimal debouncing delay should match your audience’s typing speed (typically 30 words per minute (WPM) on mobile devices and 40 WPM on desktop devices). If the delay is too short, users still see flashes of content. If the delay is too long, the time between keypresses and results becomes too long.

200 ms is the preferred debounce delay. Delays of over 300 ms will start degrading the user experience.

You should also increase the stallThreshold setting to avoid showing a “loading” spinner after the final keystroke. Set it to your debounce delay plus 300 ms.

Debounce sources

Use the debounced function for static and dynamic sources.

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
// ...
const STALL_THRESHOLD_MS = 500; // For example, 500ms for a 200ms debounce delay

autocomplete({
  container: '#autocomplete',
  stallThreshold: STALL_THRESHOLD_MS,
  getSources({ query }) {
    return debounced([
      {
        sourceId: 'algoliaItems',
        getItems() {
          return getAlgoliaResults({
            searchClient,
            queries: [
              {
                indexName: 'indexName',
                query,
              },
            ],
          });
        },
        // ...
      },
      {
        sourceId: 'staticItems',
        getItems({ query }) {
          const items = [
            { label: 'Twitter', url: 'https://twitter.com' },
            { label: 'GitHub', url: 'https://github.com' },
          ];

          return items.filter(({ label }) =>
            label.toLowerCase().includes(query.toLowerCase())
          );
        },
        // ...
      },
      {
        sourceId: 'dynamicItems',
        getItems() {
          return fetch(`https://example.org/search/?q=${query}`)
            .then((response) => response.json())
            .then(({ results }) => results)
            .catch(() => []);
        },
        // ...
      },
    ]);
  },
});
Did you find this page helpful?