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

# Animated placeholders

> Draw your users' attention to the search box by mimicking the effect of typing queries.

export const ConversionRate = () => <Tooltip tip="The percentage of searches with `clickAnalytics` set to `true` that result in at least one conversion event." cta="Conversion rate" href="/doc/guides/search-analytics/concepts/metrics#conversion-rate">
    conversion rate (CVR)
  </Tooltip>;

Animated placeholders mimic the effect of typing queries in a passive search box.
They're a good way of **drawing your users' attention to the search box and suggesting possible queries**.
Such a pattern can help increase the usage of your search box and improve <ConversionRate /> and discovery.

<Columns>
  <Card title="Open CodeSandbox" icon="codesandbox" href="https://codesandbox.io/s/github/algolia/solutions/tree/master/animated-placeholder-demo">
    Run and edit the Animated placeholders example in CodeSandbox.
  </Card>

  <Card title="View code on GitHub" icon="github" href="https://github.com/algolia/solutions/tree/master/animated-placeholder-demo">
    View the Animated placeholders example code on GitHub.
  </Card>
</Columns>

## Before you begin

This tutorial requires [InstantSearch.js](/doc/guides/building-search-ui/getting-started/js).

## High-level overview

To create an animated placeholder, you want to run some code that animates text character by character with pauses between, and injects it into the search box as placeholder text. The length of a pause should be random so it looks like actual typing. The recommended delay range of 50-90 milliseconds looks the most natural.

## Single placeholder

<Steps>
  <Step title="Add a search box">
    Add an InstantSearch `searchBox` widget and set its placeholder to an empty string.

    ```js JavaScript icon=code theme={"system"}
    search.addWidget(
      instantsearch.widgets.searchBox({
        container: "#search-box",
        placeholder: "",
        showLoadingIndicator: true,
      }),
    );
    ```
  </Step>

  <Step title="Declare constants">
    Declare the following constants:

    * The search box element
    * The delay after the animation has run
    * The animation delay between letters (a minimum and maximum value)
    * Your placeholder text.

    ```js JavaScript icon=code theme={"system"}
    const searchBar = document.querySelector(".ais-SearchBox-input");

    const DELAY_AFTER_ANIMATION = 1000;
    const MIN_ANIMATION_DELAY = 50;
    const MAX_ANIMATION_DELAY = 90;
    const PLACEHOLDER = "This is an animated placeholder";
    ```
  </Step>

  <Step title="Randomize animation time">
    Add a function that returns a random integer between a minimum and maximum value. This gets the animation time for each letter.

    ```js JavaScript icon=code theme={"system"}
    const getRandomDelayBetween = (min, max) =>
      Math.floor(Math.random() * (max - min + 1) + min);
    ```
  </Step>

  <Step title="Set the placeholder attribute value">
    Add a function that sets the value of the placeholder attribute in the search box.

    ```js JavaScript icon=code theme={"system"}
    const setPlaceholder = (inputNode, placeholder) => {
      inputNode.setAttribute("placeholder", placeholder);
    };
    ```
  </Step>

  <Step title="Animate the characters">
    1. Add a function that recursively animates all the characters from an array.

       ```js JavaScript icon=code theme={"system"}
       const animateLetters = (currentLetters, remainingLetters, inputNode) => {
         if (!remainingLetters.length) {
           return;
         }

         currentLetters.push(remainingLetters.shift());

         setTimeout(
           () => {
             setPlaceholder(inputNode, currentLetters.join(""));
             animateLetters(currentLetters, remainingLetters, inputNode);
           },
           getRandomDelayBetween(MIN_ANIMATION_DELAY, MAX_ANIMATION_DELAY),
         );
       };
       ```

    2. Add a function that makes the initial call to `animateLetters`.

       ```js JavaScript icon=code theme={"system"}
       const animatePlaceholder = (inputNode, placeholder) => {
         animateLetters([], placeholder.split(""), inputNode);
       };
       ```
  </Step>

  <Step title="Animate the placeholder">
    Add an event listener that animates the placeholder when the page loads.

    ```js JavaScript icon=code theme={"system"}
    window.addEventListener("load", () => {
      animatePlaceholder(searchBar, PLACEHOLDER);
    });
    ```
  </Step>
</Steps>

## Multiple placeholders

To animate multiple placeholders, you need to make a few changes to the code you wrote for a [single placeholder implementation](#single-placeholder).

<Steps>
  <Step title="Change placeholder constant">
    Change your `PLACEHOLDER` constant to an array of strings called `PLACEHOLDERS`,
    containing all the placeholder sentences you want to display.

    ```js JavaScript icon=code theme={"system"}
    const searchBar = document.querySelector(".ais-SearchBox-input");
    const DELAY_AFTER_ANIMATION = 1000;
    const PLACEHOLDER = "This is an animated placeholder"; // [!code --]
    const PLACEHOLDERS = [  // [!code ++]
      "This is an animated placeholder", // [!code ++]
      "Search for a green hoodie", // [!code ++]
      "Search for our latest item", // [!code ++]
      "Find your favorite movie", // [!code ++]
    ]; // [!code ++]

    const MIN_ANIMATION_DELAY = 50;
    const MAX_ANIMATION_DELAY = 90;
    ```
  </Step>

  <Step title="Select random placeholder">
    1. Add an `onAnimationEnd` callback function that selects a random (but different) placeholder string from your `PLACEHOLDERS` array and calls the `animatePlaceholder` function with the new string. This function triggers every time the animation ends.

       ```js JavaScript icon=code theme={"system"}
       const onAnimationEnd = (placeholder, inputNode) => {
         setTimeout(() => {
           let newPlaceholder = "";

           do {
             newPlaceholder =
               PLACEHOLDERS[Math.floor(Math.random() * PLACEHOLDERS.length)];
           } while (placeholder === newPlaceholder);

           animatePlaceholder(inputNode, newPlaceholder, onAnimationEnd);
         }, DELAY_AFTER_ANIMATION);
       };
       ```

    2. Change the return value of your `animateLetter` function so that it calls the `onAnimationEnd` function whenever a placeholder animation ends.

       ```js JavaScript icon=code theme={"system"}
       const animateLetters = (
         currentLetters,
         remainingLetters,
         inputNode,
         onAnimationEnd,
       ) => {
         if (!remainingLetters.length) {
           return; // [!code --]
           return ( // [!code ++]
             typeof onAnimationEnd === "function" && // [!code ++]
             onAnimationEnd(currentLetters.join(""), inputNode) // [!code ++]
           ); // [!code ++]
         }

         currentLetters.push(remainingLetters.shift());

         setTimeout(
           () => {
             setPlaceholder(inputNode, currentLetters.join(""));
             animateLetters(
               currentLetters,
               remainingLetters,
               inputNode,
               onAnimationEnd,
             );
           },
           getRandomDelayBetween(MIN_ANIMATION_DELAY, MAX_ANIMATION_DELAY),
         );
       };
       ```
  </Step>

  <Step title="Update event listener">
    Update your `load` event listener so that it passes the `onAnimationEnd` callback and the first item of your `PLACEHOLDERS` array to `animatePlaceholders`.

    ```js JavaScript icon=code theme={"system"}
    window.addEventListener('load', () => {
      // If we want multiple, different placeholders, we pass our callback.
      animatePlaceholder(
        searchBar,
        PLACEHOLDER, // [!code --]
        PLACEHOLDERS[0], // [!code ++]
        onAnimationEnd // [!code ++]
      );
    });
    ```
  </Step>
</Steps>
