Stagger Text

An animated stagger text reveal component.

Text Revealing animation made Awesome 🔥 

Usage

To use the StaggerText component, follow these steps:

  1. Installation: Install the necessary package using npm, yarn or pnpm.
npm i framer-motion clsx tailwind-merge
  1. Tailwind CSS: Install tailwind css or you can customize the styling according to your ui library

  2. Add util file: lib/utils.ts

import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
  1. Source code: Copy & paste the below code into component/ui/motion or according to your code structure
"use client";
import { cn } from "@/lib/utils";
import {
  AnimationControls,
  AnimationProps,
  cubicBezier,
  motion,
  Variants,
} from "framer-motion";
import { PropsWithChildren } from "react";

const fadeIn: Variants = {
  from: {
    opacity: 0,
  },
  to: {
    opacity: 1,
  },
};

const slideIn: Variants = {
  from: {
    opacity: 0,
    y: 140,
  },
  to: {
    opacity: 1,
    y: 0,
  },
};

const flip: Variants = {
  from: {
    opacity: 0,
    rotateX: 140,
  },
  to: {
    opacity: 1,
    rotateX: 0,
  },
};

export const animationVariants = {
  fadeIn,
  slideIn,
  flip,
};

type TVariants = typeof animationVariants;

export interface StaggerTextProps extends PropsWithChildren {
  className?: string;
  transition?: AnimationProps["transition"];
  variant?: keyof TVariants;
  controller?: AnimationControls;
}

const defaultTransition: AnimationProps["transition"] = {
  ease: cubicBezier(0.33, 1, 0.68, 1),
  duration: 0.6,
  damping: 30,
};

export function StaggerText({
  children,
  className,
  transition,
  controller,
  variant = "fadeIn",
}: StaggerTextProps) {
  if (typeof children !== "string") {
    throw Error("FadeInStaggerText can only render text content");
  }

  const words = children.split(" ");

  return (
    <motion.p
      className={cn("flex flex-wrap", className)}
      initial="from"
      animate={controller ?? "to"}
      transition={{ staggerChildren: 0.1 }}
    >
      {words.map((word, i) => (
        <Word
          key={word + i}
          variants={animationVariants[variant]}
          transition={transition}
        >
          {word}&nbsp;
        </Word>
      ))}
    </motion.p>
  );
}

interface WordProps extends PropsWithChildren {
  variants: Variants;
  transition: StaggerTextProps["transition"];
}

function Word({ children, variants, transition }: WordProps) {
  return (
    <span className="overflow-hidden">
      <motion.span
        className="block"
        variants={variants}
        transition={{ ...defaultTransition, ...transition }}
      >
        {children}
      </motion.span>{" "}
    </span>
  );
}