Scroll-Grow Section

A rounded, inset section that grows to the screen edges (and upward) as you scroll, then eases back partway as it leaves.

GSAPScrollTriggerScrub

Prompt

Build a section that grows to touch the screen edges as you scroll, using GSAP ScrollTrigger with scrub.

Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Use gsap and gsap/ScrollTrigger (call gsap.registerPlugin(ScrollTrigger)).

COMPONENT: GrowSection({ className, children }) — a client component.
- Markup: <section ref={outer}> wrapping <div ref={inner} className={className}>{children}</div>.
- The section's starting CSS matches the animation's start state, so nothing jumps before hydration:
  - padding-left/right 80px and padding-top 80px from 768px; 32px each on phones.
  - The inner div has a 64px radius from 768px (40px on phones) and its own padding (16px; 12px on phones).

ANIMATION — set up with gsap.matchMedia()
- Run one setup for "(min-width: 768px) and (prefers-reduced-motion: no-preference)" with gutter 80 and radius 64.
- Run another for "(max-width: 767px) and (prefers-reduced-motion: no-preference)" with gutter 32 and radius 40.
- Reduced motion gets no animation. Call mm.revert() on unmount.
- Read the inner div's computed padding-top once (padTop).

1) GROW IN — a timeline with scrollTrigger { trigger: section, start: "top 85%", end: "top 15%", scrub: 0.6 }:
- Section: paddingLeft/Right from gutter to 0.
- Inner: borderRadius from radius to 0. marginTop from 0 to -gutter. paddingTop from padTop to padTop + gutter.
- Use ease "none" and position 0 for both tweens.
- The negative margin pulls the top edge up while the matching extra padding keeps the content in place. Total height doesn't change, so the page below never shifts.

2) EASE BACK PARTWAY — a timeline with scrollTrigger { trigger: section, start: "bottom 85%", end: "bottom 15%", scrub: 0.6 }:
- With SHRINK = 0.4: section paddingLeft/Right from 0 to gutter × SHRINK, and inner borderRadius from 0 to radius × SHRINK.
- Use ease "none" and immediateRender: false on both, so they don't overwrite the grow state on load.
- The top is left alone, since it's already off-screen.

Everything inside the section (cards, grids) widens with it, because the layout really grows — it's not scaled.

More in Animations