How to create Typewriter text effect in React

While building the landing page of Mindsaha, I needed a way to show a text using typewriter effect. Here is the final outcome.

React Typewriter effect

Here's how I approached the problem and implemented a solution.

Designing a React Typewriter component

If you think about what a Typewriter component should do, it comes down to these points.

  1. The component accepts a text prop.
  2. It then displays the characters in the given text one by one in certain duration (i.e. 500ms). This simulates the typing effect.
  3. Once the full text has been displayed, it waits for some time.
  4. Finally, it clears the whole text, again one by one.

Once the text is cleared, the effect is done. The component then may switch to the next text or just repeat the whole process again.

With this initial design, let's get into the coding.

Coding the Typewriter component in React

import React, { useEffect, useState } from "react";

const TYPING_SPEED = 100;
const SHOW_TIME = 2000;
const DEL_SPEED = 25;

function TypeWriter({ text }) {
  const [display, setDisplay] = useState(" ");

  const [typing, setTyping] = useState(true);
  // type the characters one by one
  useEffect(() => {
    if (!text || !text.trim().length) return;
    let typingTimer;
    if (typing) {
      let idx = 0;
      typingTimer = setInterval(() => {
        if (idx <= text.length) {
          setDisplay(text.substring(0, idx));
          idx++;
        } else {
          // when all characters are typed, after SHOW_TIME set clear flag
          clearInterval(typingTimer);
          setTimeout(() => {
            setTyping(false);
            setClearing(true);
          }, SHOW_TIME);
        }
      }, TYPING_SPEED);
    }

    return () => {
      clearInterval(typingTimer);
    };
  }, [text, typing]);

  // clear the characters one by one
  const [clearing, setClearing] = useState(false);
  useEffect(() => {
    let clearTimer;
    if (clearing) {
      let idx = text.length - 1;
      clearTimer = setInterval(() => {
        if (idx >= 0) {
          setDisplay(text.substring(0, idx));
          idx--;
        } else {
          // when all characters cleared, reset and invoke the callback
          clearInterval(clearTimer);
          setClearing(false);
          setTyping(true);
        }
      }, DEL_SPEED);
    }
    return () => {
      if (clearTimer) {
        clearInterval(clearTimer);
      }
    };
  }, [clearing, text]);
  return <span>{display || text[0]}</span>;
}
export default TypeWriter;

Typewriter text effect - Demo

Here is the demo of the above component. Feel free type in new text and animate.

React Typewriter Effect - Demo

Question to you?

What do you think about this implementation? If it is up to you, how would you go about it? Also, can you think of how the blinking cursor has been done, as seen in the Mindsaha landing page?