Write a React hook useTypewriter(phrases, options) that types each phrase, pauses, backspaces it, then loops. Add ±30% jitter so it does not feel robotic.
export function useTypewriter(phrases, options = {}) {
const { typeSpeed = 80, deleteSpeed = 45,
pauseAfterType = 1800, pauseAfterDelete = 400 } = options;
const [displayText, setDisplayText] = useState("");
const [isTyping, setIsTyping] = useState(true);
const [isDeleting, setIsDeleting] = useState(false);
const phraseIndex = useRef(0);
const charIndex = useRef(0);
const timeout = useRef();
const jitter = (b) => b * (0.7 + Math.random() * 0.6);
useEffect(() => {
const tick = () => {
const phrase = phrases[phraseIndex.current];
if (!isDeleting) {
if (charIndex.current < phrase.length) {
charIndex.current++;
setDisplayText(phrase.slice(0, charIndex.current));
timeout.current = setTimeout(tick, jitter(typeSpeed));
} else {
setIsTyping(false);
timeout.current = setTimeout(() => setIsDeleting(true), pauseAfterType);
}
} else {
if (charIndex.current > 0) {
charIndex.current--;
setDisplayText(phrase.slice(0, charIndex.current));
timeout.current = setTimeout(tick, jitter(deleteSpeed));
} else {
setIsDeleting(false); setIsTyping(true);
phraseIndex.current = (phraseIndex.current + 1) % phrases.length;
timeout.current = setTimeout(tick, pauseAfterDelete);
}
}
};
timeout.current = setTimeout(tick, typeSpeed);
return () => clearTimeout(timeout.current);
}, [phrases, isDeleting]);
return { displayText, isTyping, isDeleting };
}











