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

# Predictive search suggestions

> Suggest related searches near the search box to give users shortcuts to the information they want.

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

Predictive search suggestions lets users quickly access the content they're looking for because **the most relevant suggestions appear directly inside the search box.** They can also see the most popular searches and discover more of your content.

<Columns>
  <Card title="Open CodeSandbox" icon="codesandbox" href="https://codesandbox.io/s/github/algolia/solutions/tree/master/predictive-search-box-widget-demo">
    Run and edit the Predictive search suggestions example in CodeSandbox.
  </Card>

  <Card title="View code on GitHub" icon="github" href="https://github.com/algolia/solutions/tree/master/predictive-search-box-widget-demo">
    View the Predictive search suggestions example code on GitHub.
  </Card>
</Columns>

## Before you begin

This guide requires:

* [InstantSearch.js](/doc/guides/building-search-ui/getting-started/js)
* A [Query Suggestions index](#create-a-query-suggestions-index). If you already have one, go directly to the [detailed implementation overview](#detailed-overview).

## Implementation guide

### Create a Query Suggestions index

1. Go to the **Query suggestions** tab of the dashboard.
2. Click the **New Query Suggestion** button.
3. Fill in the relevant "Name", "Languages", and "Source Index" inputs, then click the **Accept** button.

<Note>
  For more information, see [Query Suggestions](/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/js).
</Note>

### High-level overview

To create predictive search suggestions,
you overlap two containers (a search box and a predictive box),
then send your user's current query to your Query Suggestions <Index /> at every keystroke.

Based on the query, the predictive box displays and consistently updates the first result from the suggestions. You can also display other results under the search box (in a drop-down menu or a grid).

1. Wrap your search input in a container (for example, a `<div>`).
2. Declare a second container within the first one. This second container displays the suggestions.
3. Use CSS to adjust the position of the search box so that it perfectly overlaps with the suggestions container.
4. Change the text color of the suggestion container so that the query and the recommendation are distinctive.
5. At every keystroke, send the query to your Query Suggestions index.
6. Every time you get a response from the Query Suggestions index, update the text in your suggestions container with the first result that starts with the same letters as the input query. You can also display other suggestions beneath your search box if you want.

<Note>
  Predicted suggestions must begin with the same letters as your user's input.
</Note>

### Detailed overview

This guide walks you through creating a predictive search box widget, which you can import into your app.

<Steps>
  <Step title="Create search box">
    Write a render function that creates a search box with three `<div>`s:

    * The search box,
    * The overlapping predictive box
    * A display area for extra suggestions.

    ```js JavaScript icon=code theme={"system"}
    const renderSearchBoxContainer = (placeholder, value) => {
      return `
          <div id="searchbox">
            <div id="predictive-box" style="display: none;">
              <span id="predictive-box-text"></span>
            </div>
            <div class="search-box-container">
              <input autocapitalize="off"
                placeholder="${placeholder}"
                id="search-box-input"
                autocomplete="off"
                autocorrect="off"
                role="textbox"
                spellcheck="false"
                type="search"
                value="${value}">
            </div>
            <div id="clear-input"><i class="fas fa-times"></i></div>
            <fieldset id="suggestion-tags-container"></fieldset>
          </div>
        `;
    };
    ```

    The search box is composed of three main parts. This guide refers to them as:

    * The **search box**: the input field where users type in their search queries (`.search-box-container`).
    * The **predictive box**: the `<div>` that overlaps with the search box and contains the top suggestion (`.predictive-box`).
    * The **suggestions tags**: the `<div>` that contains all the extra suggestions from the Query Suggestions index (`.suggestion-tags-container`).
  </Step>

  <Step title="Style the search box">
    Write the CSS to style the search box and predictive box. The goal is to ensure:

    * The `<div>`s overlap perfectly
    * The predictive box appears behind the search box (so that your users can still type their queries)
    * The predictive box and search box have different text colors.

    ```css CSS icon=paintbrush theme={"system"}
        .search-box-container input {
          border: none;
          border-bottom: 1px solid #cecece;
          width: 100%;
          font-size: 20px;
          background: transparent;
          padding: 0 !important;
          outline: none;
          height: 100%;
          position: relative;
          z-index: 99;
          font-family: Arial, Helvetica, sans-serif;
        }

        #predictive-box {
          height: 49px;
          padding: 0 !important;
          display: flex;
          align-items: center;
          position: absolute;
          border-bottom: 1px solid transparent;
        }

        #predictive-box-text {
          font-family: Arial, Helvetica, sans-serif;
          font-size: 20px;
          color: #a2a2a2;
        }
    ```

    <Note>
      This guide doesn't include the complete CSS.
      You can find it in the [source code](https://github.com/algolia/solutions/blob/master/predictive-search-box-widget-demo/predictive-search-box/predictive-search-box.css).
    </Note>
  </Step>

  <Step title="Detect user key press">
    Define a helper function that checks if users have pressed a specific key.

    ```js JavaScript icon=code theme={"system"}
    const isKey = (event, code, name) => event.which === code || event.keyCode === code || event.key === name;
    ```
  </Step>

  <Step title="Create a predictive search box">
    1. Create a `PredictiveSearchBox` class. You'll add methods in the following steps.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         // Add methods to the class in the following steps
       }
       ```

    2. Add a constructor for the `PredictiveSearchBox`.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         constructor(options) {
           Object.assign(this, options);

           this.client = algoliasearch(options.appID, options.apiKey);
           this.querySuggestionsIndex = this.client.initIndex(
             this.querySuggestionsIndex
           );

           this.maxSuggestions = 5;
           this.tabActionSuggestion = '';
         }
       }
       ```

    3. Add an initialization method for the `PredictiveSearchBox` class.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         // ...

         init(initOptions) {
           const widgetContainer = document.querySelector(this.container);

           if (!widgetContainer) {
             throw new Error(
               `Could not find widget container ${this.container} inside the DOM.`
             );
           }

           widgetContainer.innerHTML = renderSearchBoxContainer(
             this.placeholder,
             initOptions.helper.state.query
           );

           this.predictiveSearchBox = widgetContainer.querySelector('#predictive-box');
           this.predictiveSearchBoxItem = widgetContainer.querySelector(
             '#predictive-box-text'
           );
           this.clearButton = widgetContainer.querySelector('#clear-input');
           this.searchBoxInput = widgetContainer.querySelector('#search-box-input');
           this.suggestionTagsContainer = widgetContainer.querySelector(
             '#suggestion-tags-container'
           );

           this.registerSearchBoxHandlers(
             initOptions.helper,
             this.searchBoxInput,
             this.clearButton
           );
         }
       }
       ```
  </Step>

  <Step title="Register handlers">
    Register handlers for searching, handling suggestions, tab completion, and keyboard navigation.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...

      registerSearchBoxHandlers = (helper, searchBox, clearButton) => {
        searchBox.addEventListener('input', event => this.updateTabActionSuggestion(event));
        searchBox.addEventListener('keydown', event => this.onTabSelection(event));
        clearButton.addEventListener('click', event => this.clear(event));
        searchBox.addEventListener('input', event => {
          helper.setQuery(event.currentTarget.value).search();
        });
      };
    }
    ```
  </Step>

  <Step title="Add setter method">
    Add a setter method for the value of the search box input.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...

      setSearchBoxValue = value => {
        this.searchBoxInput.value = value;
        this.searchBoxInput.dispatchEvent(new Event('input'));
      };
    }
    ```
  </Step>

  <Step title="Set search box value to the suggestion in the predictive search box">
    Add a handler method that calls `setSearchBoxValue` to set the search box value to the suggestion displayed in the predictive box when users press the right arrow.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...

      onTabSelection = event => {
        if (!isKey(event, 39, 'ArrowRight')) return;

        event.preventDefault();
        this.setSearchBoxValue(this.tabActionSuggestion);
      };
    }
    ```
  </Step>

  <Step title="Update suggestions">
    Add a method that updates the suggestions tags based on the new hits from the query response.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...

      updateSuggestionTags = hits => {
        if (!this.maxSuggestions || this.maxSuggestions <= 0) return hits;
        this.clearSuggestionTags();

        hits.slice(0, this.maxSuggestions).forEach(suggestion => {
          const suggestionElement = document.createElement('button');
          suggestionElement.classList.add('suggestion-tag');
          suggestionElement.innerHTML = suggestion._highlightResult.query.value;

          suggestionElement.addEventListener('click', () => {
            this.setSearchBoxValue(suggestion.query);
          });
          this.suggestionTagsContainer.append(suggestionElement);
        });
      };
    }
    ```
  </Step>

  <Step title="Search Query Suggestions index">
    Add a method that dispatches a search on your Query Suggestions index and uses the results to update the suggestions in the predictive box and suggestions tags. This method triggers whenever the query changes.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...

      updateTabActionSuggestion = event => {
        const query = event.currentTarget.value;

        if (!query) {
          this.predictiveSearchBox.style.display = 'none';
          this.clearButton.style.display = 'none';
          return;
        }

        this.querySuggestionsIndex
          .search({ query })
          .then(response => {
            const suggestions = response.hits.filter(hit =>
              hit.query.startsWith(query)
            );

            if (!suggestions.length) {
              this.clearPredictiveSearchBox();
              return [];
            }

            this.predictiveSearchBox.style.display = 'flex';
            this.predictiveSearchBoxItem.innerText = suggestions[0].query;
            this.tabActionSuggestion = suggestions[0].query;
            return suggestions.slice(1);
          })
          .then(this.updateSuggestionTags);
      };
    }
    ```
  </Step>

  <Step title="Clear suggestions">
    1. Add a method that removes all suggestions tags so they can be updated.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         // ...

         clearSuggestionTags = () => {
           this.suggestionTagsContainer.innerHTML = '';
         };
       }
       ```

    2. Add a method that removes the predictive box suggestion.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         // ...

         clearPredictiveSearchBox = () => {
           this.tabActionSuggestion = '';
         };
       }
       ```

    3. Add a method that clears all suggestion content from your search container, letting you update it with new suggestions.

       ```js JavaScript icon=code theme={"system"}
       class PredictiveSearchBox {
         // ...

         clear = event => {
           this.searchBoxInput.value = '';
           this.predictiveSearchBoxItem.innerText = '';
           this.clearSuggestionTags();

           this.tabActionSuggestion = '';
           event.target.style.display = 'none';
           searchBoxInput.dispatchEvent(new Event('input'));
         };
       }
       ```
  </Step>

  <Step title="Export predictive search box">
    Export the `PredictiveSearchBox` class so you can import it into your app.

    ```js JavaScript icon=code theme={"system"}
    class PredictiveSearchBox {
      // ...
    }

    export default PredictiveSearchBox;
    ```
  </Step>
</Steps>
