← Back toCSS Animation

Typing indicator

Written byPhuoc Nguyen
Created
01 Sep, 2023
In messaging apps and chat interfaces, you might have noticed a little pattern called the tying indicator. It shows when the person you're talking to is typing a message. This can take different forms, from a simple dot-dot-dot to fancier animations or progress bars. The idea is to let you know when to expect a reply and to reassure you that your message has been received and is getting attention.
In this post, we'll explore how to create a typing indicator using CSS animation.

Markup

The indicator consists of three ellipses, which are empty elements. As a result, the layout can be kept simple with the following structure:
index.html
<div class="container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
To make each dot look like a circle, we simply need to set the same value for both the `height` and `width` properties. Additionally, we can set the border radius to 50% of the dimension to achieve the desired effect.
styles.css
.dot {
border-radius: 9999px;
height: 0.5rem;
width: 0.5rem;
}
To ensure the dots align horizontally and are displayed at the center of the container, we can utilize CSS flexbox styles applied to the container. It's easy to achieve this with just a few lines of code.
styles.css
.container {
align-items: center;
display: flex;
justify-content: center;
gap: 0.25rem;
}
The `gap` property of a container determines the space between the dots representing its children.
To indicate to our users that something is in progress, we can create a simple animation that fades in and out a series of dots. First, we'll set the opacity of all the dots to 0 to make them invisible. Then, in the middle of the animation, we'll update the opacity to 1, creating a blink effect.
styles.css
@keyframes blink {
50% {
opacity: 1;
}
}
We'll run the animation for 1 second and repeat it infinitely.
styles.css
.dot {
animation: blink 1s infinite;
opacity: 0;
}
Although we expected a smooth animation, when three dots start and finish animations at the same time, it doesn't look as slick as we would like. One solution is to animate each dot individually, providing users with a better experience.
We'll start by animating the first dot, followed by the second dot once the first one completes its animation. The last dot will then run its animation once the second dot finishes its job.
Luckily, this can be easily achieved in CSS by using the `animation-delay` property. If the overall animation will be played over 1 second, we can delay the animation for each dot accordingly.
styles.css
.dot:nth-child(1) {
animation-delay: 0.3333s;
}
.dot:nth-child(2) {
animation-delay: 0.6666s;
}
.dot:nth-child(3) {
animation-delay: 0.9999s;
}
In this example, we use the `:nth-child` selector to select a dot by its corresponding index. For instance, `:nth-child(1)` will select the first dot element, and so on.
Now, the moment has arrived to witness the final result of what we've been working on so far!

Waving effect

In this section, we'll explore a different kind of animation that moves a dot up and down vertically. By running animations for our dots at different points in the timeline, we can make the container look like a sine wave.
To achieve this effect, we can use the `transform` property. The first and last phases won't change the position of each dot. However, in the middle phase, each dot will move up. We'll use the `translateY` function with a negative number to reposition the target element vertically, from bottom to top.
styles.css
@keyframes wave {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-0.5rem);
}
100% {
transform: translateY(0px);
}
}
To create a smoother effect, try changing the position and opacity of each phrase in combination, as demonstrated below:

Adding a speech bubble

Lots of messaging and chat apps use speech bubbles as their container design. You can follow the technique outlined in this post to add this shape to your indicator.
Check out this example, which includes two smaller circles in the bottom-left corner of the container.
In this example, we've created a keyframe called "zoom" which scales up the target using the `scale` function. The target is scaled down to its original size when the animation starts and completes its cycle. Then, in the middle of the animation, the target is scaled up to 110%.
style.css
@keyframes zoom {
50% {
transform: scale(1.1);
}
}
In addition to the animated dots, the container also zooms in and out using keyframes that last for 2 seconds and have an `ease-out` timing function. This animation runs on an infinite loop.
style.css
.container {
animation: 2s zoom infinite ease-out;
}

See also

Questions? 🙋

Do you have any questions? Not just about this specific post, but about any topic in front-end development that you'd like to learn more about? If so, feel free to send me a message on Twitter or send me an email. You can find them at the bottom of this page.
I have a long list of upcoming posts, but your questions or ideas for the next one will be my top priority. Let's learn together! Sharing knowledge is the best way to grow 🥷.

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn