Creating a typewriter animation using Tailwind CSS and Next.js

I am currently working on implementing a typewriter effect that is almost exactly how I want it. However, I am facing an issue with the printing process. Right now, each word gets printed on a new line and falls into place when done printing. What I actually want is for each word to be printed and then continue on the next line before reaching a certain point within the container.

Here's my global.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

.typewriter {
  border-right: 0px solid;
  width: 100%;
  white-space: normal;
  overflow: hidden;
  animation: typing 2s steps(40), cursor .4s step-end infinite alternate;
}

@keyframes cursor {
  50% {
    border-color: transparent;
  }
}

@keyframes typing {
  from {
    width: 0;
  }
}

body {
  @apply bg-gray-100;
}

page.js:

'use client';
import { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCircle } from '@fortawesome/free-solid-svg-icons';
import { useRouter } from 'next/navigation'; 

export default function LandingPage() {
  const [phraseIndex, setPhraseIndex] = useState(0);
  const [fadeIn, setFadeIn] = useState(true);
  const router = useRouter();

  useEffect(() => {
    const interval = setInterval(() => {
      setFadeIn(false);
      setTimeout(() => {
        setPhraseIndex((prevIndex) => (prevIndex + 1) % userSearchExamples.length);
        setFadeIn(true);
      }, 500); 
    }, 5000);

    return () => clearInterval(interval);
  }, [phraseIndex]);

  const handleLoginClick = () => {
    router.push('/login');
  };

  const handleRegisterClick = () => {
    router.push('/register');
  }; 

  const userSearchExamples = [
    "Find me an outfit for a night out",
    "What would go well with a grey hoodie?",
    "I need a dress for a wedding",
    "I need a casual outfit for a date",
    "What should I wear to a job interview?",
    "Help me find an outfit for a vacation"
  ];

  return (
    <main>
      <div className="w-full h-screen grid grid-cols-5">
        <div className="col-span-3 bg-customColor">
          <p className="text-purple-400 p-1 font-bold inline-flex gap-2 text-2xl items-center absolute left-5 top-5">
            FashionFinder
            <FontAwesomeIcon icon={faCircle} className="w-5" />
          </p>
          <div className="h-full flex items-center">
            <p className={`typewriter text-purple-400 text-4xl font-semibold text-left ml-4 mr-5 ${fadeIn ? 'fade-in' : 'fade-out'}`} key={phraseIndex}>
              {userSearchExamples[phraseIndex]}
            </p>
          </div>
        </div>
        <div className="col-span-2 bg-black flex flex-col items-center justify-center">
          <p className="text-3xl font-bold text-white">
            Get started
          </p>
          <div className='flex gap-4 w-full p-6'>
            <button
              className="p-4 bg-blue-700 font-bold w-full rounded-lg shadow-xl text-white"
              onClick={handleLoginClick}>
              Login
            </button>
            <button
              className='p-4 bg-blue-700 font-bold w-full rounded-lg shadow-xl text-white'
              onClick={handleRegisterClick}>
              Register
            </button>
          </div>
        </div>
      </div>
    </main>
  )
}

Answer №1

To achieve the typewriter effect, you can modify your CSS in the following way:

.typewriter {
  text-transform: none!important;
  overflow: hidden;
  border-right: .2em solid blue;
  white-space: nowrap;
  margin: 0; /* Adjust margin for alignment */
  letter-spacing: .15em;
  animation: typing-animation 4s steps(40, end), blink-caret-animation .75s step-end infinite;
}
@keyframes typing-animation {
  from { width: 0 }
  to { width: 100% }
}
@keyframes blink-caret-animation {
  from, to { border-color: transparent }
  50% { border-color: blue; }
}

Alternatively, you can implement the effect using Tailwind CSS only by following these steps:

  1. Update your Tailwind configuration as shown below:
module.exports = {
  theme: {
    extend: {
      animation: {
        typewriter: 'typewriter 2s steps(11) forwards',
        caret: 'typewriter 2s steps(11) forwards, blink 1s steps(11) infinite 2s',
      },
      keyframes: {
        typewriter: {
          to: {
            left: '100%',
          },
        },
        blink: {
          '0%': {
            opacity: '0',
          },
          '0.1%': {
            opacity: '1',
          },
          '50%': {
            opacity: '1',
          },
          '50.1%': {
            opacity: '0',
          },
          '100%': {
            opacity: '0',
          },
        },
      },
    },
  },
  plugins: [],
}

Now, apply the typewriter effect like this:

<h2 class="relative w-[max-content] font-sans before:absolute before:inset-0 before:animate-typewriter before:bg-white after:absolute after:inset-0 after:w-[0.125em] after:animate-caret after:bg-black">Greetings</h2>

Feel free to check out a Live Demo of the effect.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to position a div alongside a fluid div with minimum and maximum widths

Within this container, there is a div. #leftBanner { height: 100%; background-color: #CCC; width: 22%; min-width: 245px; max-width: 355px; float: left; } This particular div doesn't cooperate when I try to float another div next to it. While I could ...

Encountering an internal server error when using Next.js API routes with Nodemailer

Using cPanel to host my Next.js website, I encountered an issue with an API route that uses Nodemailer to send messages. While the route works perfectly fine on localhost and Vercel, every time I call it on the live server, I receive an internal server err ...

Tips for Setting Up Next.js 13 Route Handlers to Incorporate a Streaming API Endpoint via LangChain

I am currently working on establishing an API endpoint using the latest Route Handler feature in Nextjs 13. This particular API utilizes LangChain and streams the response directly to the frontend. When interacting with the OpenAI wrapper class, I make sur ...

Ensuring that images are the perfect size for their parent container

Exploring the functionalities of angular bootstrap carousel, I am eager to showcase various images and enable clicking on them. The challenge I'm facing is that my images are not uniform in size and don't fit perfectly within my bootstrap column ...

Tips for stacking objects vertically in mobile or tablet view using HTML and CSS

I have been diligently working on a project using a fiddle, and everything appears to be running smoothly in desktop view. The functionality is such that upon clicking any two product items (with one remaining selected by default), a detailed description ...

How can you integrate a Custom Provider with NextAuth?

After following the NextAuth.js documentation, I successfully implemented login with github, which was quite simple and easy to do. The implementation can be found in pages/auth/[...nextauth].js: import NextAuth from "next-auth"; import GithubPr ...

What is the best way to dynamically implement text ellipsis using CSS in conjunction with Angular 7?

i need to display a list of cards in a component, each card has a description coming from the server. In my component.html, I am using a ngFor like this: <div [style.background-image]="'url('+row.companyId?.coverUrl+')'" class="img- ...

Adjust transparency in Bootstrap slider with picture indicator

Currently, I am in the process of creating an HTML page featuring a Bootstrap carousel. To enhance user interaction, I have replaced the standard selector with images that, when clicked, will transition the slider to display corresponding content. In orde ...

Discovering the way to retrieve background height following a window resize using jQuery

Is there a way to obtain the background height once the window has been resized? div { background-image: url(/images/somebackground.jpg); background-size: 100% 90%; background-repeat: no-repeat; width: 70%; background-size: contain; ...

Various text sizes within a nested HTML list structure

I've developed a nested CSS class for an ordered list on my website, but I'm encountering a problem where each list item is appearing in different font sizes even though I have specified the font size. .number_list ol { font:normal 1.2em ...

Learn how to display a web page in a tab view similar to the toggle device toolbar option

Is it possible to simulate the toggle device toolbar of a web page using JavaScript? https://i.stack.imgur.com/M9oB0.png For example, can we set up a webpage to always display in tab or mobile view like on YouTube? ...

Make sure the image is aligned in line with the unordered list

I've been having trouble trying to display an image inline with an unordered list. Here's the HTML code: <div class="customer-indiv man"> <a class="customer_thumb" href="/fan/332profile.com"> <img src="http://i.imgur.com/Wi ...

What is preventing me from adjusting the padding of the mat-button?

Trying to adjust the default padding of a mat-button, but encountering issues with changing the component's style. Any suggestions on how to subscribe to the default padding (16px)? I've attempted modifying CSS properties to set the padding of a ...

Issues arise when attempting to alter the background image using jQuery without browserSync being activated

I am facing an issue with my slider that uses background-images and BrowserSync. The slider works fine when BrowserSync is running, but without it, the animations work properly but the .slide background image does not appear at all. Can someone help me ide ...

"Adjusting the margin for dropdowns in a Bootstrap navbar

Is there a way to customize the alignment of the bootstrap navbar drop-down? Currently, the drop down menu always starts from the right corner. I would like to set a specific starting point for the drop-down. You can view an example in this Fiddle. When ...

Locate numbers 2, 3, 6, 7, and 10, and continue in numerical order, within the

Having trouble with this one. Does anyone know how to display the items like this: 2, 3, 6, 7, 10 and so on... Is there a jQuery or CSS hack that can achieve this? I'm stuck trying to figure it out .container { display: flex; flex-flow: row wra ...

What is the best way to showcase a String variable with spaces in the value field of a form within JSP?

When working with a String variable in JSP and trying to display it in a form field, there might be an issue if the string contains spaces. Only the first word is displayed instead of the entire sentence. Below is the code snippet along with the resulting ...

Using the `import '~.......` statement within a NextJS project

I'm struggling to figure out where the symbol ~ is designated in a NextJS import. It doesn't seem to point to the user's home folder, as it does in Linux. In one of my projects, it directs me to the project's root folder, while in anoth ...

Can anyone help me with fixing the error message 'Cannot assign to read-only property 'exports' of the object' in React?

Recently, I decided to delve into the world of React and started building a simple app from scratch. However, I have run into an issue that is throwing the following error: Uncaught TypeError: Cannot assign to read-only property 'exports' of o ...

Display all attribute connections for a product in Prestashop

I have updated the products in my shop to include different combinations. These combinations involve a 'packaging' attribute with two options: a 100 units box and a 200 units box, each with its own unique reference number. On the product page, t ...