Build websites 10x faster with HextaUI Blocks — Learn more
Original Blocks/Text

Typewriter

A typewriter effect for text animations.

|
<Typewriter text="HextaAI is typing..." />

Installation

Copy and paste the following code into your project.

components/ui/Typewriter.tsx
"use client";

import { useEffect, useState } from "react";

export interface TypewriterProps {
  text: string | string[];
  speed?: number;
  cursor?: string;
  loop?: boolean;
  deleteSpeed?: number;
  delay?: number;
  className?: string;
}

export function Typewriter({
  text,
  speed = 100,
  cursor = "|",
  loop = false,
  deleteSpeed = 50,
  delay = 1500,
  className,
}: TypewriterProps) {
  const [displayText, setDisplayText] = useState("");
  const [currentIndex, setCurrentIndex] = useState(0);
  const [isDeleting, setIsDeleting] = useState(false);
  const [textArrayIndex, setTextArrayIndex] = useState(0);

  // Validate and process input text
  const textArray = Array.isArray(text) ? text : [text];
  const currentText = textArray[textArrayIndex] || "";

  useEffect(() => {
    if (!currentText) return;

    const timeout = setTimeout(
      () => {
        if (!isDeleting) {
          if (currentIndex < currentText.length) {
            setDisplayText((prev) => prev + currentText[currentIndex]);
            setCurrentIndex((prev) => prev + 1);
          } else if (loop) {
            setTimeout(() => setIsDeleting(true), delay);
          }
        } else {
          if (displayText.length > 0) {
            setDisplayText((prev) => prev.slice(0, -1));
          } else {
            setIsDeleting(false);
            setCurrentIndex(0);
            setTextArrayIndex((prev) => (prev + 1) % textArray.length);
          }
        }
      },
      isDeleting ? deleteSpeed : speed,
    );

    return () => clearTimeout(timeout);
  }, [
    currentIndex,
    isDeleting,
    currentText,
    loop,
    speed,
    deleteSpeed,
    delay,
    displayText,
    text,
  ]);

  return (
    <span className={className}>
      {displayText}
      <span className="animate-pulse">{cursor}</span>
    </span>
  );
}
npx shadcn@latest add "https://21st.dev/r/hextaui/typewriter-text"
pnpm dlx shadcn@latest add "https://21st.dev/r/hextaui/typewriter-text"
yarn dlx shadcn@latest add "https://21st.dev/r/hextaui/typewriter-text"
bun x shadcn@latest add "https://21st.dev/r/hextaui/typewriter-text"

Usage

import { Typewriter } from "@/components/ui/Typewriter";
<Typewriter text="HextaAI is typing..." />

Props

PropTypeDefault
className?
string
""
delay?
number
1500
deleteSpeed?
number
50
loop?
boolean
false
cursor?
string
"|"
speed?
number
100
text?
string | string[]
"HextaAI is typing..."
Edit on GitHub

Last updated on