Block Reveal Text Animation

Simple text animation build in Next.js using GSAP SplitText.

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Assumenda tenetur quam deleniti dolores quaerat, autem optio! In, pariatur officia. Suscipit quas officiis blanditiis quaerat minus, possimus dolorum voluptatum perspiciatis corporis.

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
  • SplitText Plugin
  • useGSAP Plugin
  • Tailwind CSS
components/animated-text.tsx
"use client";

import { ReactNode, useRef } from "react";
import gsap from "gsap";
import { SplitText } from "gsap/SplitText";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(SplitText, useGSAP);

const DURATION = 0.45;

export function AnimatedText({ children }: { children: ReactNode }) {
  const containerRef = useRef<HTMLDivElement | null>(null);

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

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

        SplitText.create(containerRef.current, {
          type: "lines",
          autoSplit: true,
          linesClass: "animated-line",
          mask: "lines",
          onSplit: (self) => {
            self.lines.forEach((element, index) => {
              const blockLineDiv = document.createElement("div");
              blockLineDiv.className = "block-line absolute top-0 left-0 bg-yellow-200 right-full h-full";
              element.appendChild(blockLineDiv);
              const textContent = element.firstChild;

              gsap.set(textContent, {
                clipPath: "inset(0 100% 0 0)",
              });

              const delay = 0.1 * index;
              const tl = gsap.timeline({ delay });

              tl.to(blockLineDiv, {
                right: 0,
                duration: DURATION,
                ease: "power1.inOut",
              });
              tl.to(blockLineDiv, {
                left: "100%",
                duration: DURATION,
                ease: "power1.inOut",
              });
              tl.to(
                textContent,
                {
                  clipPath: "inset(0 0% 0 0)",
                  duration: DURATION,
                  ease: "power1.inOut",
                },
                "<"
              );
            });
          },
        });
      }

      startAnimating();
    },
    {
      scope: containerRef,
    }
  );

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

<AnimatedText>
  <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>