How can I assist you today?
Installation
Install the following dependencies:
pnpm add motion
Create a file at components/motion/text-loop.tsx
and paste the given code.
"use client";
import { cn } from "@/lib/utils";
import {
motion,
AnimatePresence,
Transition,
Variants,
AnimatePresenceProps,
} from "motion/react";
import { useState, useEffect, Children } from "react";
export type TextLoopProps = {
children: React.ReactNode[];
className?: string;
interval?: number;
transition?: Transition;
variants?: Variants;
onIndexChange?: (index: number) => void;
trigger?: boolean;
mode?: AnimatePresenceProps["mode"];
};
export function TextLoop({
children,
className,
interval = 2,
transition = { duration: 0.6 },
variants,
onIndexChange,
trigger = true,
mode = "popLayout",
}: TextLoopProps) {
const [currentIndex, setCurrentIndex] = useState(0);
const items = Children.toArray(children);
useEffect(() => {
if (!trigger) return;
const intervalMs = interval * 1000;
const timer = setInterval(() => {
setCurrentIndex((current) => {
const next = (current + 1) % items.length;
onIndexChange?.(next);
return next;
});
}, intervalMs);
return () => clearInterval(timer);
}, [items.length, interval, onIndexChange, trigger]);
const motionVariants: Variants = {
initial: { y: 20, opacity: 0 },
animate: { y: 0, opacity: 1 },
exit: { y: -20, opacity: 0 },
};
return (
<div
className={cn("relative inline-block whitespace-nowrap", className)}
>
<AnimatePresence mode={mode} initial={false}>
<motion.div
key={currentIndex}
initial="initial"
animate="animate"
exit="exit"
transition={transition}
variants={variants || motionVariants}
>
{items[currentIndex]}
</motion.div>
</AnimatePresence>
</div>
);
}