April 8, 2026/Simple/Page Transitions

Scale + Slide From Left Transition

Page elements scale up from zero and slide in from the left while fading in. Long 0.25s stagger gives a theatrical, sequential feel. Most dramatic of the GSAP transition patterns.

Home

  • Featured Work
  • Latest Projects
  • Studio
"use client";

import { useEffect, useRef, useState } from "react";
import gsap from "gsap";
import styles from "./styles.module.css";

const PAGES = [
  { label: "Home", bg: "#f5f5f5", color: "#1a1a1a", items: ["Featured Work", "Latest Projects", "Studio"] },
  { label: "Projects", bg: "#0d0d0d", color: "#ffffff", items: ["All Projects", "Case Studies", "Archive"] },
  { label: "About", bg: "#1a1a2e", color: "#ffffff", items: ["Story", "Team", "Process"] },
];

export default function ScaleSlideLeftTransition() {
  const [pageIndex, setPageIndex] = useState(0);
  const [displayIndex, setDisplayIndex] = useState(0);
  const containerRef = useRef(null);
  const isAnimating = useRef(false);

  function navigate(nextIndex) {
    if (isAnimating.current || nextIndex === pageIndex) return;
    isAnimating.current = true;

    const container = containerRef.current;
    gsap.to(container, {
      opacity: 0,
      duration: 0.3,
      ease: "power1.in",
      onComplete: () => {
        setDisplayIndex(nextIndex);
        setPageIndex(nextIndex);
      },
    });
  }

  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const items = container.querySelectorAll(`.${styles.item}`);
    if (!items.length) return;

    // Enter: scale from 0 + slide from left, long 0.25s stagger
    gsap.fromTo(
      items,
      { opacity: 0, scale: 0, x: -30 },
      {
        opacity: 1,
        scale: 1,
        x: 0,
        stagger: 0.25,
        duration: 0.6,
        ease: "power2.out",
        onStart: () => gsap.set(container, { opacity: 1 }),
        onComplete: () => { isAnimating.current = false; },
      }
    );
  }, [displayIndex]);

  const page = PAGES[displayIndex];

  return (
    <div className={styles.demo}>
      <div
        ref={containerRef}
        className={styles.page}
        style={{ background: page.bg, color: page.color }}
      >
        <h2 className={styles.pageTitle}>{page.label}</h2>
        <ul className={styles.list}>
          {page.items.map((item) => (
            <li key={item} className={styles.item}>{item}</li>
          ))}
        </ul>
      </div>
      <div className={styles.nav}>
        {PAGES.map((p, i) => (
          <button
            key={p.label}
            className={`${styles.navBtn} ${i === pageIndex ? styles.active : ""}`}
            onClick={() => navigate(i)}
          >
            {p.label}
          </button>
        ))}
      </div>
    </div>
  );
}
  • gsap

Related Components

1W AGO
Signifly Theme Fadepage-transitions
3MO AGO
Section Transition Systempage-transitions
3MO AGO
Shutter Sectionpage-transitions