The typewriter effect

I first saw the typewriting effect on a friend's personal website, and I found it very pleasing, so, when I started building my website, I just knew I had to use it somewhere.

My first approach was using a third party library, and I quickly found typed.js, which was super easy to install and setup, and gave me no troubles whatsoever. However, I liked the idea of doing the effect by myself.

A few months later I found this css-tricks post, explaining how to do the typewriting with JS, and I knew this was the perfect chance to build a React component and stop relying on the external library.

It turned out to be much simpler than I had anticipated, and, although this component has way less features than the library, it suited my needs and allowed me to remove one dependency from my project. Plus, the component is very style agnostic, so it's pretty simple to reuse

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

const TypedContent = ({ sentences=[] })=> {
  
  const [text, setText] = useState("")
  const [currentSentence, setCurrentSentence] = useState(0)
  const [isDeleting, setDeleting] = useState(false)
  
  const tick = ()=> {
    const sentence = sentences[currentSentence]
    const new_text = sentence
      .substring(0, text.length + (isDeleting ? -1 : +1))
    setText(new_text)
  }
  
  useEffect(()=> setDeleting(false), [currentSentence])
  
  useEffect(()=> {
    const sentence = sentences[currentSentence]
    // Sentence complete - wait & set to deleting
    if (!isDeleting && sentence === text) {
      const timeout = setTimeout(()=> setDeleting(true), 1000)
      return ()=> clearTimeout(timeout)
    }
    // Sentence deleted - wait & advance sentence
    if (isDeleting && !text) {
      const timeout = setTimeout(()=> {
        const total = sentences.length
        setCurrentSentence(current=> (current+1)%total)
      }, 500)
      return ()=> clearTimeout(timeout)
    }
    // Add or remove a letter (δ = typing speed)
    const delta = 80
    const timeout = setTimeout(tick, isDeleting ? delta/2 : delta)
    return ()=> clearTimeout(timeout)
  }, [text, isDeleting, currentSentence])
  
  return (
    <span
      className="TypedContent"
      data-status={`${sentences[currentSentence] === text ? "done" : "active"}`}
    >
      {text}
    </span>
  )
}

That's it! That's the whole component! It works out of the box & it does not require any special CSS, it will inherit size, color & other style properties from its container. Modifying the delta value, and the timeouts will change the typing speed.

If you don't plan on adding anything else, you can probably delete the className and the data-status attributes. I put them there, because it allows me to create the blinking caret effect with this tiny bit of extra CSS.

.TypedContent {
  border-right: 2px solid rgba(255, 255, 255, .8);
  padding-right: 3px;
}

.TypedContent[data-status="complete"] {
  animation: typedBorderEdge .5s infinite alternate linear;
}

@keyframes typedBorderEdge {
  from {
    border-right: 2px solid rgba(255, 255, 255, .8);
  }
  to {
    border-right: 2px solid rgba(255, 255, 255, .05);
  }
}

And that's that, I sincerely hope you en

More concepts