ComponentsText Animations

Typewriter Text

React typewriter effect with customizable speed, cursor styles, and word deletion. Perfect for hero sections and dynamic text displays.

Last updated on

Edit on GitHub
"use client";
 
import { TypewriterText } from "@/components/ui/typewritter-text";
 
export function TypewritterTextDemo() {
  return (
    <div className="flex items-center justify-center">
      <TypewriterText
        words={["Hello", "World", "Typewriter", "Effect"]}
        className="font-bold text-4xl text-foreground"
      />
    </div>
  );
}

Examples

Variants

"use client";
 
import { TypewriterText } from "@/components/ui/typewritter-text";
 
export function TypewritterTextCustomDemo() {
  return (
    <div className="flex flex-col items-center justify-center gap-8">
      <div className="text-center">
        <h3 className="mb-4 font-semibold text-lg">Fast Typing</h3>
        <TypewriterText
          words={["Code", "Build", "Deploy", "Scale"]}
          typingSpeed={50}
          deletingSpeed={25}
          pauseDuration={1000}
          className="font-mono text-2xl text-primary"
        />
      </div>
 
      <div className="text-center">
        <h3 className="mb-4 font-semibold text-lg">Slow Typing</h3>
        <TypewriterText
          words={["Design", "Create", "Innovate", "Inspire"]}
          typingSpeed={200}
          deletingSpeed={100}
          pauseDuration={3000}
          className="font-bold text-3xl text-destructive"
        />
      </div>
    </div>
  );
}

Installation

CLI

npx shadcn@latest add "https://jolyui.dev/r/typewritter-text"

Manual

Install the following dependencies:

npm install motion

Copy and paste the following code into your project. component/ui/typewritter-text.tsx

import { motion } from "motion/react";
import * as React from "react";
import { cn } from "@/lib/utils";
 
interface TypewriterTextProps {
  words: string[];
  className?: string;
  typingSpeed?: number;
  deletingSpeed?: number;
  pauseDuration?: number;
  cursorClassName?: string;
}
 
const TypewriterText = React.forwardRef<HTMLSpanElement, TypewriterTextProps>(
  (
    {
      words,
      className,
      typingSpeed = 100,
      deletingSpeed = 50,
      pauseDuration = 1500,
      cursorClassName,
    },
    ref,
  ) => {
    const [currentWordIndex, setCurrentWordIndex] = React.useState(0);
    const [currentText, setCurrentText] = React.useState("");
    const [isDeleting, setIsDeleting] = React.useState(false);
 
    React.useEffect(() => {
      const currentWord = words[currentWordIndex] || "";
 
      const timeout = setTimeout(
        () => {
          if (!isDeleting) {
            if (currentText.length < currentWord.length) {
              setCurrentText(currentWord.slice(0, currentText.length + 1));
            } else {
              setTimeout(() => setIsDeleting(true), pauseDuration);
            }
          } else {
            if (currentText.length > 0) {
              setCurrentText(currentText.slice(0, -1));
            } else {
              setIsDeleting(false);
              setCurrentWordIndex((prev) => (prev + 1) % words.length);
            }
          }
        },
        isDeleting ? deletingSpeed : typingSpeed,
      );
 
      return () => clearTimeout(timeout);
    }, [
      currentText,
      isDeleting,
      currentWordIndex,
      words,
      typingSpeed,
      deletingSpeed,
      pauseDuration,
    ]);
 
    return (
      <span ref={ref} className={cn("inline-block", className)}>
        {currentText}
        <motion.span
          animate={{ opacity: [1, 0] }}
          transition={{
            duration: 0.5,
            repeat: Infinity,
            repeatType: "reverse",
          }}
          className={cn(
            "ml-0.5 inline-block h-[1em] w-[2px] bg-current align-middle",
            cursorClassName,
          )}
        />
      </span>
    );
  },
);
TypewriterText.displayName = "TypewriterText";
 
export { TypewriterText };

API Reference

Prop

Type

Notes

  • Uses motion/react for smooth blinking cursor animation
  • Automatically cycles through words with typing and deleting effects
  • Supports custom CSS classes for styling text and cursor
  • Configurable typing speed, deleting speed, and pause duration
  • Perfect for hero sections, loading states, or dynamic content

How is this guide?

On this page