Animated Placeholder
This guide uses an outdated version of Autocomplete. Algolia recommends using Autocomplete v1 instead.
To migrate from v0 to v1, please refer to the upgrade guide.
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 bar and suggesting possible queries for them. Such a pattern can help increase the usage of your search box, and improve conversion rate and discovery.
Requirements
Difficulty |
|
Prerequisites | Instant Search 3+ |
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 bar 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
Add an InstantSearch searchBox
widget and set its placeholder to an empty string.
1
2
3
4
5
6
7
search.addWidget(
instantsearch.widgets.searchBox({
container: '#search-box',
placeholder: '',
showLoadingIndicator: true
})
);
Declare the following constants:
- the search bar element,
- the delay after the animation has run,
- the animation delay between letters (a min and max value),
- and your placeholder text.
1
2
3
4
5
6
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';
Add a function which returns a random integer between a minimum and maximum value. This is helpful to get the animation time for each letter.
1
const getRandomDelayBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
Add a function which sets the value of the placeholder attribute in the search box.
1
2
3
const setPlaceholder = (inputNode, placeholder) => {
inputNode.setAttribute("placeholder", placeholder);
};
Add a function which recursively animates all the characters from an array.
1
2
3
4
5
6
7
8
9
10
11
12
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));
};
Add a function that makes the initial call to animateLetters
.
1
2
3
const animatePlaceholder = (inputNode, placeholder) => {
animateLetters([], placeholder.split(''), inputNode);
};
Finally, add an event listener that animates the placeholder when the page loads.
1
2
3
window.addEventListener('load', () => {
animatePlaceholder(searchBar, PLACEHOLDER);
});
Multiple placeholders
To animate multiple placeholders, you need to make a few changes to the code you wrote for a single placeholder implementation.
Change your PLACEHOLDER
constant to an array of strings called PLACEHOLDERS
, containing all the placeholder sentences you want to display.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...
const searchBar = document.querySelector('.ais-SearchBox-input');
const DELAY_AFTER_ANIMATION = 1000;
- const PLACEHOLDER = 'This is an animated placeholder';
+ const PLACEHOLDERS = [
+ 'This is an animated placeholder',
+ 'Search for a green hoodie',
+ 'Search for our latest item',
+ 'Find your favorite movie'
+];
const MIN_ANIMATION_DELAY = 50;
const MAX_ANIMATION_DELAY = 90;
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.
1
2
3
4
5
6
7
8
9
10
11
12
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);
};
Change the return value of your animateLetter
function so that it calls the onAnimationEnd
function whenever a placeholder animation ends.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const animateLetters = (
currentLetters,
remainingLetters,
inputNode,
onAnimationEnd
) => {
if (!remainingLetters.length) {
- return
+ return (
+ typeof onAnimationEnd === 'function' &&
+ onAnimationEnd(currentLetters.join(''), inputNode)
+ );
}
currentLetters.push(remainingLetters.shift());
setTimeout(() => {
setPlaceholder(inputNode, currentLetters.join(''));
animateLetters(currentLetters, remainingLetters, inputNode, onAnimationEnd);
}, getRandomDelayBetween(MIN_ANIMATION_DELAY, MAX_ANIMATION_DELAY));
};
Update your load
event listener so that it passes the onAnimationEnd
callback and the first item of your PLACEHOLDERS
array to animatePlaceholders
.
1
2
3
4
5
6
7
8
9
10
window.addEventListener('load', () => {
// If we want multiple, different placeholders, we pass our callback.
animatePlaceholder(
searchBar,
- PLACEHOLDER
+ PLACEHOLDERS[0],
+ onAnimationEnd
);
});