Introducing Motion-Primitives Pro - Advanced components and templates to help you build a website that stands out.

Text Loop

Text animation that transitions between multiple items, creating an engaging looping effect

Examples

Text Loop Basic

How can I assist you today?

Text Loop with custom variants and transition

Beautiful templates for

Founders

Text Loop with onIndexChange

You can use the onIndexChange prop to trigger a callback function when the index changes. In this example, we use it to create alternating animation directions.

A Little Lost・Arthur Russell

Code

'use client';
import { cn } from '@/lib/utils';
import { motion, AnimatePresence, Transition, Variants } from 'framer-motion';
import { useState, useEffect, Children } from 'react';

type TextLoopProps = {
  children: React.ReactNode[];
  className?: string;
  interval?: number;
  transition?: Transition;
  variants?: Variants;
  onIndexChange?: (index: number) => void;
};

export function TextLoop({
  children,
  className,
  interval = 2,
  transition = { duration: 0.3 },
  variants,
  onIndexChange,
}: TextLoopProps) {
  const [currentIndex, setCurrentIndex] = useState(0);
  const items = Children.toArray(children);

  useEffect(() => {
    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]);

  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='popLayout' initial={false}>
        <motion.div
          key={currentIndex}
          initial='initial'
          animate='animate'
          exit='exit'
          transition={transition}
          variants={variants || motionVariants}
        >
          {items[currentIndex]}
        </motion.div>
      </AnimatePresence>
    </div>
  );
}

Component API

Text Loop

PropTypeDefaultDescription
childrenReact.ReactNode[]The text content to be animated.
classNamestringAdditional CSS classes for styling.
intervalnumber2000Time interval between text changes in milliseconds.
transitionTransitionAnimation transition settings. Can't be more than inerval
variantsVariantsCustom animation variants.
onIndexChange(index: number) => voidCallback function that triggers when the index changes.