How to create Typewriter effect that is accessible & SEO friendly

I was recently asked to make a hero section of a website more engaging by giving it a typewriter effect. Should be easy enough I thought, right?? (Typewriter effect: making letters of the text appear one at a time, ChatGPT like)

And as any good developer out there, I began by looking for an already existing example that I could just copy & paste. I found multiple examples implementing it in slightly different ways, but most of them suffered from 2 BIG issues.

The way I found it implemented in was to start with the html element empty, store the final text somewhere, & then using setTimeout they append one letter at a time to the innerHtml property of the element.

This gave the intended visual effect, but as I mentioned, it presented 2 big issues that I couldn’t ignore:

1- It was not accessible.

Because screen readers will initially find the element to be empty, and then the text will gradually be updated, so it won’t figure how to pronounce it correctly. (We could use aria-hidden while the animation is happening, & then remove it once done, but the user will most likely have moved to a different section at that time)

2- It was not SEO friendly.

Since the web crawler either don’t run JS or run JS but don’t wait for long, they will likely see the element empty. So if this piece of text was something important for the indexing of the web page like the name of the product or the tagline, it’ll have a bad effect.

So how did I end up doing it?

After thinking about it for a bit & some experimenting I came to a solution that gave me the intended visual effect while not suffering from the above mentioned issues.

If you only want to jump to the final code, here is a Codepen that I created for it:

See the Pen Accessible Typewriter Effect by Mohammed Taher Ghazal (@mtg_dev) on CodePen.

But if you want to know more about the approach, read on.

So the basic idea of the solution is to keep the text fully in the html from the start. & let it take the full width it needs, just hide it visually using something like color: transparent (It’s still visible to screen readers & crawlers)

What we will do is to create an ::after element for each text node. This after element will get its content value from an attribute on its parent element that we will call something like data-content. We will fill the data-content attribute from JavaScript one letter at a time. & using CSS, we will position the after element on top of its parent element so that it will take the exact same styling & space.

Not too complicated, right?

Here is the styling of the after element:

.typewriter > *::after {
  content: attr(data-content);
  color: var(--font-color, white);
  position: absolute;
  left: 0;
  top: 0;
}

And here is the JavaScript code that will update the data-content attribute.

const paragraphs = document.querySelectorAll(".typewriter > *");

let currentLetter = 0;
let currentParagraph = 0;

const typeWriter = () => {
  if (currentLetter < paragraphs[currentParagraph].textContent.length) {
    paragraphs[currentParagraph].setAttribute(
      "data-content",
      paragraphs[currentParagraph].textContent.slice(0, currentLetter + 1)
    );
    currentLetter++;
  } else {
    currentParagraph++;
    currentLetter = 0;
  }

  if (currentParagraph === paragraphs.length) return;

  if (currentLetter === paragraphs[currentParagraph].textContent.length)
    setTimeout(typeWriter, 500);
  else setTimeout(typeWriter, 50);
};

typeWriter();

We are just going through each paragraph, one letter at a time, & between each paragraph we leave a small delay (500 ms) You can change the speed of the effect by changing the timeout values.

& yeah, that’s basically it!

As I mentioned earlier, I’ve created a CodePen for it that you could check for the full code here:

See the Pen Accessible Typewriter Effect by Mohammed Taher Ghazal (@mtg_dev) on CodePen.

If you found this useful, let me know in the comments & share it with others.

Until next time,
& have a nice day. 👋

My Photo

About Me

I'm a freelance web developer who specializes in frontend.
I have a special love for React. And my personal goal is: Building things that are Awesome! ✨
If you are someone who is building a project where high quality is a MUST, then Let's Chat! I'll be glad to help you with it.

© 2023-present Mohammed Taher Ghazal. All Rights Reserved.