TypeWriter Effect
A typewriter effect component for displaying animated text..
Introduction
A typewriter effect component for displaying animated text.
Demo
Installation
To install the TypeWriter component, you can use npm or yarn. Run one of the following commands in your project directory:
npx shadcn@latest add https://ahs-lab.vercel.app/r/TypeWriterEffect.jsonCode
"use client";
import { motion } from "motion/react";
import React, { useState, useEffect } from "react";
interface TextProps {
texts?: string[];
}
interface TypewriterProps {
texts: string[];
}
const TypewriterEffect = ({ texts = ["beautiful.", "modern.", "elegant.", "minimal."] }: TextProps) => {
return (
<h1 className="inline-block relative w-[320px] overflow-hidden text-7xl font-bold tracking-tighter text-left md:text-center mt-10">
<motion.span
initial={{ width: "0%" }}
animate={{ width: "100%" }}
transition={{ duration: 0.3, ease: "easeInOut", delay: 0.5 }}
className="w-full absolute bottom-0 left-0 h-[70px] bg-lime-500/10 block"
/>
<motion.span
initial={{ width: "0%" }}
animate={{ width: "100%" }}
transition={{ duration: 0.3, ease: "easeInOut", delay: 0.5 }}
className="w-full absolute bottom-0 left-0 h-1 bg-lime-500 block"
/>
<Typewriter texts={texts} />
</h1>
);
};
export default TypewriterEffect;
const Typewriter = ({ texts }: TypewriterProps) => {
const [currentTextIndex, setCurrentTextIndex] = useState(0);
const [currentText, setCurrentText] = useState("");
const [isDeleting, setIsDeleting] = useState(false);
const [showCursor, setShowCursor] = useState(true);
useEffect(() => {
const typeSpeed = isDeleting ? 100 : 150;
const fullText = texts[currentTextIndex];
const timeout = setTimeout(() => {
if (!isDeleting && currentText === fullText) {
// Finished typing current word, wait then start deleting
setTimeout(() => setIsDeleting(true), 2000);
} else if (isDeleting && currentText === "") {
// Finished deleting, move to next word
setIsDeleting(false);
setCurrentTextIndex((prev) => (prev + 1) % texts.length);
} else {
// Continue typing or deleting
setCurrentText(
isDeleting
? fullText.substring(0, currentText.length - 1)
: fullText.substring(0, currentText.length + 1)
);
}
}, typeSpeed);
return () => clearTimeout(timeout);
}, [currentText, currentTextIndex, isDeleting, texts]);
// Cursor blinking effect
useEffect(() => {
const cursorInterval = setInterval(() => {
setShowCursor((prev) => !prev);
}, 500);
return () => clearInterval(cursorInterval);
}, []);
return (
<span className="inline-block">
<span className="text-primary">{currentText}</span>
<span
className={`inline-block w-0.5 h-16 bg-lime-500 ml-1 ${
showCursor ? "opacity-100" : "opacity-0"
} transition-opacity duration-100`}
/>
</span>
);
};