A captivating typewriter effect component that animates text with realistic typing and deleting animations. Perfect for hero sections, landing pages, and dynamic content displays!
npm i clsx tailwind-merge motionlib/utils.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Typewriter.tsx
"use client"
import { useState, useEffect } from "react"
import { cn } from "@/lib/utils"
interface TypewriterProps {
text: string[]
speed?: number
deleteSpeed?: number
waitTime?: number
className?: string
cursorChar?: string
showCursor?: boolean
loop?: boolean
}
export default function Typewriter({
text,
speed = 100,
deleteSpeed = 50,
waitTime = 2000,
className = "",
cursorChar = "|",
showCursor = true,
loop = true,
}: TypewriterProps) {
const [currentText, setCurrentText] = useState("")
const [currentIndex, setCurrentIndex] = useState(0)
const [isDeleting, setIsDeleting] = useState(false)
const [showCursorBlink, setShowCursorBlink] = useState(true)
useEffect(() => {
const timeout = setTimeout(
() => {
const current = text[currentIndex]
if (isDeleting) {
setCurrentText(current.substring(0, currentText.length - 1))
} else {
setCurrentText(current.substring(0, currentText.length + 1))
}
if (!isDeleting && currentText === current) {
setTimeout(() => setIsDeleting(true), waitTime)
} else if (isDeleting && currentText === "") {
setIsDeleting(false)
setCurrentIndex((prevIndex) => {
if (!loop && prevIndex === text.length - 1) {
return prevIndex
}
return (prevIndex + 1) % text.length
})
}
},
isDeleting ? deleteSpeed : speed,
)
return () => clearTimeout(timeout)
}, [currentText, currentIndex, isDeleting, text, speed, deleteSpeed, waitTime, loop])
useEffect(() => {
const cursorInterval = setInterval(() => {
setShowCursorBlink((prev) => !prev)
}, 500)
return () => clearInterval(cursorInterval)
}, [])
return (
<span className={cn("inline-block", className)}>
{currentText}
{showCursor && <span className={cn("ml-1", showCursorBlink ? "opacity-100" : "opacity-0")}>{cursorChar}</span>}
</span>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
| text | string[] | - | Array of strings to cycle through |
| speed | number | 100 | Typing speed in milliseconds |
| deleteSpeed | number | 50 | Deleting speed in milliseconds |
| waitTime | number | 2000 | Wait time before deleting in milliseconds |
| className | string | "" | Additional CSS classes |
| cursorChar | string | "|" | Character to use as cursor |
| showCursor | boolean | true | Whether to show the blinking cursor |
| loop | boolean | true | Whether to loop through text array |