Slide Up Reveal Text Animation

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eligendi labore iusto sit ex tenetur inventore.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolor ea laborum, accusamus blanditiis incidunt provident ipsum amet eligendi facere perferendis eos dicta quis, natus omnis repellat ratione doloremque vitae perspiciatis ipsam debitis obcaecati. Ullam incidunt natus accusamus cum eos iure! Beatae quasi rem ad repudiandae voluptatum ut. Corporis, neque earum.

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Autem veniam ducimus rem fuga. Explicabo maiores aspernatur aut reprehenderit harum esse quasi? Magnam fugit natus nesciunt commodi ut ullam rem amet.

  • Next.js
  • Typescript
  • GSAP
  • ScrollTrigger Plugin
  • SplitText Plugin
  • useGSAP Plugin
  • Tailwind CSS
components/animated-text.tsx
"use client";
import React, { useRef } from "react";
import gsap from "gsap";
import { SplitText } from "gsap/SplitText";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(SplitText, ScrollTrigger);

interface AnimatedTextProps {
  children: React.ReactNode;
  animateOnScroll?: boolean;
  delay?: number;
  className?: string;
}

export function AnimatedText({
  children,
  animateOnScroll = true,
  delay = 0,
  className,
}: AnimatedTextProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const splitRefs = useRef<SplitText[]>([]);

  useGSAP(
    () => {
      if (!containerRef.current) return;

      async function initializeAnimation() {
        await document.fonts.ready;

        const container = containerRef.current!;
        const elements = Array.from(container.children)

        const allLines: HTMLElement[] = [];
        splitRefs.current = [];

        for (const element of elements) {
          if (!(element instanceof HTMLElement)) continue;

          const split = SplitText.create(element, {
            type: "lines",
            mask: "lines",
            linesClass: "line++",
            lineThreshold: 0.1,
          });

          splitRefs.current.push(split);
          split.lines.forEach((line) => {
            line.classList.add(
              "relative",
              "will-change-transform",
              "pb-[0.2em]",
              "-mb-[0.2em]",
            );
          });

          allLines.push(...(split.lines as HTMLElement[]));
        }

        if (allLines.length === 0) return;

        gsap.set(allLines, { y: "100%" });
        const animationConfig = {
          y: "0%",
          duration: 1,
          stagger: 0.1,
          ease: "power4.out" as const,
          delay,
          ...(animateOnScroll && {
            scrollTrigger: {
              trigger: container,
              start: "top 90%",
              once: true,
            },
          }),
        };

        gsap.to(allLines, animationConfig);
      }

      initializeAnimation();

      return () => {
        splitRefs.current.forEach((split) => split?.revert());
      };
    },
    { scope: containerRef, dependencies: [animateOnScroll, delay] },
  );

  return (
    <div ref={containerRef} className={className}>
      {children}
    </div>
  );
}

<AnimatedText delay={0.2}>
  <p className="text-3xl">
    Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eligendi
    labore iusto sit ex tenetur inventore.
  </p>
</AnimatedText>
<AnimatedText delay={0.5}>
  <p>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolor ea
    laborum, accusamus blanditiis incidunt provident ipsum amet eligendi
    facere perferendis eos dicta quis, natus omnis repellat ratione
    doloremque vitae perspiciatis ipsam debitis obcaecati. Ullam
    incidunt natus accusamus cum eos iure! Beatae quasi rem ad
    repudiandae voluptatum ut. Corporis, neque earum.
  </p>
  <p>
    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Autem
    veniam ducimus rem fuga. Explicabo maiores aspernatur aut
    reprehenderit harum esse quasi? Magnam fugit natus nesciunt commodi
    ut ullam rem amet.
  </p>
</AnimatedText>