25

Replicating the Algolia documentation search with Autocomplete

 2 years ago
source link: https://www.algolia.com/blog/ux/replicating-the-algolia-documentation-search-with-autocomplete/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Replicating the Algolia documentation search with Autocomplete

May 4th 2021

They say an API is as good as its documentation, but good docs go beyond content quality. Technical documentation offers a taste of how interacting with the API will feel like. For many developers, it’s the main gate to your product. Miss on this experience, and they might move on to the next similar product.

There’s no single recipe to making docs stand out; you need to identify what sets it apart and address it creatively. Yet, the common denominator most users expect is fast, relevant, and well-designed search experience. At Algolia, we recently redesigned our documentation search using our open-source Autocomplete library.

The new Algolia documentation searchThe new Algolia documentation search

Autocomplete is a JavaScript library for building autocomplete search experiences. Its v0 has been successfully powering production search experiences for years. After a year’s worth of research and hard work, we’ve finally released the v1 stable, taking autocomplete search experiences to the next level.

Autocomplete has been running the Algolia documentation search experience for several months, and we’ve received many requests to teach how we built it. We’re excited to see other docs leverage the patterns we’ve come up with, so we decided to publish an in-depth guide to teach you how to build a similar search experience with Autocomplete.

Getting started

First, you need to create a new JavaScript project. An ideal starting point is a minimal Parcel setup, with an index.html document and an index.js entry point. You’ll also need Babel to transpile JSX templates.

You can fork or download this CodeSandbox vanilla JavaScript starter and use it as a base.

Installing dependencies

This tutorial uses @algolia/autocomplete-js along with Preact for templating. Once you have the project set up, you need the following dependencies:

  • @algolia/autocomplete-js to build the search experience
  • @algolia/autocomplete-theme-classic to make it look nice
  • algoliasearch to retrieve search results from Algolia
  • preact as your virtual DOM implementation

The @algolia/autocomplete-js package is an agnostic virtual DOM implementation of Autocomplete. You can use it within a React or Vue project if you don’t want to use Preact. If you don’t want to use JSX at all, you can still build virtual DOM nodes by hand using the provided implementation for createElement and Fragment.

Run the following command in your terminal to install them in your project:

yarn add @algolia/autocomplete-js @algolia/autocomplete-theme-classic algoliasearch preact
npm install @algolia/autocomplete-js @algolia/autocomplete-theme-classic algoliasearch preact

Initializing your autocomplete

To get started, you need to create a new autocomplete instance and attach it to the DOM. Autocomplete accepts several sources for each set of results you want to display. In our case, we’ll start with a single set of Algolia hits using the algoliasearch API client and the provided getAlgoliaResults helper.

In your HTML, add an empty container with an id. This is where Autocomplete will inject the search experience.

<div id="autocomplete"></div>

Then, initialize your autocomplete in your JavaScript code and attach it to your #autocomplete container.

import { autocomplete } from '@algolia/autocomplete-js';
autocomplete({
  container: '#autocomplete',
  getSources() {
    return [];

We have a working autocomplete instance! Granted, it doesn’t return anything yet, as the getSources method currently returns an empty array. We need to define where to retrieve the data to display and describe how Autocomplete should interact with them.

Defining data sources

A source is a JavaScript object that implements a given interface. At the bare minimum, it requires a unique sourceId to identify the source and a getItems function to return the data.

Sources can be synchronous or asynchronous. In our case, we can initialize an Algolia search client and retrieve items using the getAlgoliaResults helper. You can make as many queries as you need and pass them any Algolia search parameters.

import algoliasearch from 'algoliasearch/lite';
import { autocomplete, getAlgoliaResults } from '@algolia/autocomplete-js';
const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
autocomplete({
  container: '#autocomplete',
  getSources() {
    return [
        sourceId: 'hits',
        getItems({ query }) {
          return getAlgoliaResults({
            searchClient,
            queries: [
                indexName: 'instant_search',
                query,
                params: {
                  hitsPerPage: 8,

Finally, we need to let Autocomplete know how to render hits. Sources let you define templates for each item. The @algolia/autocomplete-js package expects templates as virtual DOM nodes, so we’ll use Preact to provide them via JSX.

/** @jsx h */
import { h } from 'preact';
import algoliasearch from 'algoliasearch/lite';
import { autocomplete, getAlgoliaResults } from '@algolia/autocomplete-js';
import '@algolia/autocomplete-theme-classic';
const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
autocomplete({
  container: '#autocomplete',
  getSources() {
    return [
        // ...
        templates: {
          item({ item, components }) {
            return (
              <a className="aa-ItemLink" href={item.url}>
                <div className="aa-ItemContent">
                  <div className="aa-ItemIcon">
                    <img
                      src={item.image}
                      alt={item.name}
                      width="40"
                      height="40"
                    />
                  </div>
                  <div className="aa-ItemContentBody">
                    <div className="aa-ItemContentTitle">
                      <components.Highlight hit={item} attribute="name" />
                    </div>
                  </div>
                </div>
              </a>

Make sure your project has Babel installed so that JSX templates get transpiled into h() calls.

Note that we’ve imported @algolia/autocomplete-theme-classic, a sleek-looking starter theme that’s fully compatible with Autocomplete and its plugins. We’re also leveraging Autocomplete’s Component API (see the provided components object), which lets you declare components to reuse anywhere in your experience. By default, Autocomplete provides Algolia-compatible highlighting and snippeting components.

This should give you a working autocomplete experience that renders as-you-type, highlighted search results. That’s a good start, but we’re still far from the kind of experience we have on the Algolia documentation. Let’s do this ✨

Search in a modal

Most autocomplete experiences use a drop-down list to display results below the search input. This is a typical pattern on e-commerce websites like Amazon or general-purpose search engines like Google and DuckDuckGo. On the Algolia documentation, we’re using a search modal instead to benefit from more screen real estate. This creates a more immersive experience that goes full screen on mobile devices.

Autocomplete makes it painless to switch to a modal search with detached mode. Going “detached” means detaching the autocomplete from the page and displaying it on top. By default, Detached Mode triggers on smaller screens to display a full screen autocomplete.

You can enable Detached Mode for all screen sizes by passing an empty string to the detachedMediaQuery option.

autocomplete({
  // ...
  detachedMediaQuery: '',

This should replace your search box with a search button in the document. Click it, and you’ll open your search experience in a modal 🔥

Keyboard support

No modern web interactive experience is complete without keyboard support. In a search experience, you need to conveniently switch between typing your query and browsing results without having to reach for your mouse.

Autocomplete implements the WAI-ARIA 1.1 combo box design pattern, meaning it comes with keyboard accessibility out of the box. You can use the up and down directional arrows to go through results and hit Escape to close the search modal.

When you find the right result, you want to navigate to it in a single keystroke. Autocomplete provides a Navigator API that lets you determine where to navigate when hitting Enter. All you need to do is implement the getItemUrl function in your source to provide the URL to navigate to.

autocomplete({
  // ...
  getSources() {
    return [
        // ...
        getItemUrl({ item }) {
          return item.url;

When hitting Enter while an item is active, Autocomplete will use this function with the Location API to navigate to the provided URL.

If you’re implementing your search experience in an application that uses a JavaScript-based router for internal navigation (e.g., Gatsby Link API, Next.js Router), you can implement the navigate function of the Navigator API to use this custom router instead.

You’ll notice that no search result is selected by default: you need to hit the Down key once to select the first item. In our case, we’re building an as-you-type experience where each keystroke triggers a search request, and we’re navigating to results using the Enter key, so there’s no need to manually trigger searches.

You can enable automatic selection by setting the defaultActiveItemId option to 0. This pre-selects the first item and lets you cycle through results.

autocomplete({
  // ...
  defaultActiveItemId: 0,

Mixing different types of results

Do you remember when Google’s search results looked like this?

Google search results back in 1998 | Source: Ionos.fr
Google search results back in 1998 | Source: Ionos.fr

Fast-forwarding over 20 years later, the overall layout didn’t evolve much, but Google has radically changed the way it displays results. Search for “macbook”, and you’ll get a mix of organic textual results, images, stories, answers (“people also ask”), geolocated resellers, review videos, related searches, and more. This brings variety and caters to more users looking for different things, even though they type the same query.

On the Algolia docs, we mix search results with Query Suggestions. This eliminates the need for pagination and let users quickly refine their query when they’re unsatisfied with the results. Autocomplete lets you pass as many sources as you want, making it straightforward to mix result types and customize the way they look.

With Autocomplete, there are two ways to add Query Suggestions:

Manually setting up an extra source

This technique is the one we used on the Algolia documentation. It allows us to fully control the placement of Query Suggestions and use it as a substitute for pagination. All you need to do is add an entry to the array returned by getSources.

autocomplete({
  // ...
  getSources() {
    return [
        // ...
        sourceId: 'suggestions',
        getItems({ query }) {
          return getAlgoliaResults({
            searchClient,
            queries: [
                indexName: 'instantsearch_query_suggestions',
                query,
                params: {
                  hitsPerPage: 4,

With templates, you can define what each item should look like and set a header before the list.

autocomplete({
  // ...
  getSources() {
    return [
      // ...
        sourceId: 'suggestions',
        // ...
        templates: {
          header({ items, Fragment }) {
            if (items.length === 0) {
              return null;
            return (
              <Fragment>
                <span className="aa-SourceHeaderTitle">
                  Can't find what you're looking for?
                </span>
                <div className="aa-SourceHeaderLine" />
              </Fragment>
          item({ item, components }) {
            return (
              <div className="aa-QuerySuggestion">
                <components.ReverseHighlight hit={item} attribute="query" />
              </div>

Autocomplete sources display in the defined order, so in this case, it adds up to four Query Suggestions at the end of the results list.

Unlike with search results, we don’t want to navigate to another page when selecting a suggestion. Instead, we want to “type-ahead” (or “tap-ahead” on mobile): update the query with the suggestion and trigger a new search. To do so, you can leverage the onSelect hook on the source to set the query, open the panel, and refresh the state.

autocomplete({
  // ...
  getSources() {
    return [
      // ...
        sourceId: 'suggestions',
        // ...
        onSelect({ item, setQuery, setIsOpen, refresh }) {
          setQuery(`${item.query} `);
          setIsOpen(true);
          refresh();

A helpful UX touch is to always append a space after the query. This saves a keystroke for users who want to keep on typing, and makes no difference on Algolia’s side.

Using the Query Suggestions plugin

Another search pattern you can find on sites like Amazon or Google consists of having suggestions at the top of the list to help users complete their query more efficient. This is particularly useful on mobile, where the fat-finger effect makes typing more cumbersome.

Autocomplete provides an official Query Suggestions plugin to add such suggestions to your experience, without the need to add a source manually. Check the examples on the documentation to see how to integrate the plugin into your experience.

Showing detailed information in a preview panel

Unlike a search results page, an autocomplete tends to keep results compact. This lets you show more of them, but it limits how much information you can expose.

On the Algolia docs, we solved this problem with a preview panel inspired by the macOS Spotlight experience. This lets you discover more about a given search result before deciding whether you want to navigate to the associated resource or not.

A preview panel helps you display many results while exposing in-depth information about the active item.
A preview panel helps you display many results while exposing in-depth information about the active item

Autocomplete provides several mechanisms you can leverage to put together a preview panel:

  • A Context API to store and retrieve arbitrary data anywhere in the autocomplete lifecycle.
  • A render function that outputs the autocomplete panel, open for you to customize.
  • Each source implements an onActive hook that runs whenever an item becomes active.

First, you need to implement the onActive method in your source. It lets you access all autocomplete setters, including a setContext function which lets you persist arbitrary data. You can use it to store the active item to display in the preview panel later.

autocomplete({
  // ...
  getSources() {
    return [
        sourceId: 'hits',
        // ...
        onActive({ item, setContext }) {
          setContext({ preview: item });
      // ...

Whenever you browse a search result, the value of preview changes. You can now display this data in a panel next to the list of results using the autocomplete’s render function.

The default render implementation is the following:

import { render } from 'preact';
autocomplete({
  // ...
  render({ children }, root) {
    render(children, root);

When it’s time to re-render, Autocomplete passes the current tree of virtual DOM nodes to Preact’s render function, which renders it into the panel container. We can override it to customize what to render.

Autocomplete’s render function lets you access the current state, on which you can retrieve the context. This lets you build the preview panel and display the data from the currently active item.

/** @jsx h */
import { h, render } from 'preact';
// ...
autocomplete({
  // ...
  render({ children, state, Fragment, components }, root) {
    const { preview } = state.context;
    render(
      <Fragment>
        <div className="aa-Grid">
          <div className="aa-Results aa-Column">{children}</div>
          <div className="aa-Preview aa-Column">
            <div className="aa-PreviewImage">
              <img src={preview.image} alt={preview.name} />
            </div>
            <div className="aa-PreviewTitle">
              <components.Highlight hit={preview} attribute="name" />
            </div>
            <div className="aa-PreviewPrice">${preview.price}</div>
            <div className="aa-PreviewDescription">
              <components.Highlight hit={preview} attribute="description" />
            </div>
          </div>
        </div>
      </Fragment>,

You’ll need to write some custom CSS to adjust the UI and display both columns side by side. You can find an example in the CodeSandbox of the finished project.

And there you go! Every time you scroll through results, the panel updates with a detailed view. This is a fantastic opportunity to get creative and expose relevant information to help users decide if they picked the right search results. Depending on your use case, you could showcase links to sibling pages in other programming languages (technical documentation), the most upvoted positive and negative reviews (e-commerce, media), available size and color variations (retail), etc.

The final Autocomplete implementation | Source code on CodeSandbox
The final Autocomplete implementation | Source code on CodeSandbox

Using Autocomplete with DocSearch

If you have an open-source API with an existing documentation site, you might already be using DocSearch, our free search solution for technical documentation. DocSearch comes with a front-end UI (built with Autocomplete), but you can swap it out for a custom one.

To do so, you need to replace the application ID and API key with the ones you’re using in your existing DocSearch implementation. Also, make sure to match the structure of your DocSearch records in your Autocomplete templates. You can see what your current record structure looks like by making a search on your site and inspecting the network response from Algolia.

Inspecting the Algolia search response for a DocSearch implementation in the browserInspecting the Algolia search response for a DocSearch implementation in the browser

What’s next

This gives you a taste of the kind of advanced search experiences you can build with Autocomplete and minimal user code. We’re already working on new APIs and plugins to let you go even further, and bring powerful as-you-type search capabilities to your project.

Here’s a peek at what you can expect in the near future:

  • Exposed state setters and getters to programmatically control Detached Mode
  • A Tags API to refine autocomplete results in the same interface
  • A Combine API to transform groups of sources
  • A Flow API to design graph-like navigation scenarios through results
  • And many more improvements 👀

Stay tuned about future releases on our Discourse forum, and come show us what you build with Autocomplete!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK