React and Tailwind CSS: Making a Typewriter Animation from Scratch
Tags: tailwindcss, nextjs, react, uiux
Published: 2023-05-21 18:33:03

In the world of web design, animations are pivotal in adding life and character to a website, making it more appealing and engaging. Among the multitude of animations available, the typewriter effect has a certain charm, transporting users back to a bygone era where each keystroke mattered. This effect can add a touch of nostalgia to any web interface, making content stand out in a unique way. Despite its complex appearance, it's surprisingly straightforward to implement, especially when using the power and versatility of React and Tailwind CSS.

In this article, we are going to take you on a journey back in time. We'll guide you through creating a typewriter animation, using the contemporary, yet beautifully simple technologies, React and Tailwind CSS. Whether you're looking to add a retro touch to your website, enhance your portfolio, or just learn a new skill, this guide has you covered. Ready to dive into the past with modern tools? Let's get started!

<iframe src="https://player.vimeo.com/video/828808117?h=c0352dc83d" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>

---

## The Component

```jsx
// @/components/Home/TypeWriter.js
import React, { useState, useEffect } from 'react'

export default function TypeWriter({ appendClass, hats, prefix }) {
    // Outer container base class + append custom class
    let className = "flex flex-col gap-4";
    if (appendClass) className += " " + appendClass;

    // Typewriter effect base class
    const typeWriterClass = "font-bold border-b-2 border-b-blue-400 border-r-2 pr-1"
        + "animate-cursor overflow-hidden whitespace-nowrap transition-[width] ease-in-out duration-1000 mr-auto";

    // State of current hat index
    const [currentHat, setCurrentHat] = useState(0);
    // State to toggle word collapse effect
    const [collapseClass, setCollapseClass] = useState(" w-0");

    useEffect(() => {
        setTimeout(() => setCollapseClass(" w-full"), 100);

        const incrementHat = async () => {
            // Set the width to 0 - transition duration is 1000ms
            setCollapseClass(" w-0");
            setTimeout(() => {
                /**
                 * After 1100ms, change the displayed text while the div
                 * is collapsed by incrementing the index
                 */
                setCurrentHat(oldVal => {
                    let hatIndex;
                    if (oldVal >= hats.length - 1) {
                        hatIndex = 0;
                    } else {
                        hatIndex = oldVal + 1;
                    }

                    return hatIndex;
                });
            }, 1100);
            // After 1000ms, set width to 100% - transition duration is 1000ms
            setTimeout(() => {
                setCollapseClass(" w-full");
            }, 1000);
        }
        // Interval timer to change text every 4000ms
        const id = setInterval(incrementHat, 4000);

        // Cleanup interval timer
        return () => clearInterval(id);
    }, []); //  eslint-disable-line react-hooks/exhaustive-deps

    return (
        <div className={className}>
            <div className="text-5xl md:text-6xl text-center mx-auto">
                Jay <span className="text-blue-400 font-bold">Simons</span>
            </div>
            <div className="flex gap-2 text-2xl md:text-4xl mx-auto">
                <div className="shrink-0 whitespace-nowrap ml-auto">
                    {prefix}
                    {hats[currentHat].prep ? ` ${hats[currentHat].prep} ` : ''}
                </div>
                <div className={`${typeWriterClass}${collapseClass}`}>{hats[currentHat].suffix}</div>
            </div>
        </div>
    )
}
```

This component takes a prop called `hats`, formatted as follows:

```js
const hats = [
  {
    prep: 'a',
    suffix: 'Web Developer'
  },
  {
    prep: 'a',
    suffix: 'UI/UX Designer'
  },
  {
    prep: 'a',
    suffix: 'Graphics Designer'
  },
];
```

The key `prep` is so that the typewriter displays the correct indefinite article prepending the suffix.

## Enjoy! 🤗

[Demo Site](https://jay.designly.biz)

---

Thank you for taking the time to read my article and I hope you found it useful (or at the very least, mildly entertaining). For more great information about web dev, systems administration and cloud computing, please read the [Designly Blog](https://blog.designly.biz). Also, please leave your comments! I love to hear thoughts from my readers.

I use [Hostinger](https://hostinger.com?REFERRALCODE=1J11864) to host my clients' websites. You can get a business account that can host 100 websites at a price of $3.99/mo, which you can lock in for up to 48 months! It's the best deal in town. Services include PHP hosting (with extensions), MySQL, Wordpress and Email services.

Looking for a web developer? I'm available for hire! To inquire, please fill out a [contact form](https://designly.biz/contact).