Components

Typewriter Text

A typewriter effect component that types and deletes words with a blinking cursor animation.

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