Components
Typewriter Text
A typewriter effect component that types and deletes words with a blinking cursor animation.
Last updated on
"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 motionCopy 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?