---
title: 'Advanced Scroll'
excerpt: 'ScrollTrigger.batch, horizontal containerAnimation, and refresh.'
icon: 'ScrollText'
---

## Beyond one trigger

Once you have basic reveal and pin, two patterns show up often: **batching** many similar elements efficiently, and **fake horizontal** galleries driven by vertical scroll. Both still use ScrollTrigger — they just scale the idea.

## Batch enter

Creating one ScrollTrigger per card is fine for dozens, wasteful for hundreds. `ScrollTrigger.batch` groups elements that enter near the same time and hands you an array in `onEnter` — one staggered tween for the batch.

Scroll the grid: cards fade up as clusters enter. `onLeaveBack` resets them so scrolling up can replay the entrance.

<ComponentPreview flush previewClassName="min-h-[300px]">
  <GsapScrollBatch />

  <DocsFileTabs title="Scroll batch">

```tsx title="scroll-batch.tsx"
ScrollTrigger.batch('.card', {
  scroller: stageRef.current,
  start: 'top 90%',
  onEnter: (batch) => gsap.to(batch, { autoAlpha: 1, y: 0, stagger: 0.08, overwrite: true }),
  onLeaveBack: (batch) => gsap.set(batch, { autoAlpha: 0, y: 30, overwrite: true }),
});
```

```html title="scroll-batch-markup.html"
<div class="grid grid-cols-2 gap-2">
  <div class="gsap-batch-card rounded-lg border bg-card p-3">Card 1</div>
  <div class="gsap-batch-card rounded-lg border bg-card p-3">Card 2</div>
  <!-- …more .gsap-batch-card items -->
</div>
```

  </DocsFileTabs>
</ComponentPreview>

## Fake horizontal scroll

Pin a wide track and scrub `xPercent` so vertical scroll feels like a horizontal slideshow. The horizontal tween **must** use `ease: 'none'` — any ease would desync scroll distance from panel travel.

`end` is based on track width so longer galleries get more scroll runway. Watch panels slide sideways while you scroll the stage vertically.

<ComponentPreview flush previewClassName="min-h-[200px]">
  <GsapHorizontalGallery />

  <DocsFileTabs title="Horizontal gallery">

```tsx title="horizontal-gallery.tsx"
gsap.to(panels, {
  xPercent: -100 * (panels.length - 1),
  ease: 'none', // required
  scrollTrigger: {
    trigger: wrap,
    scroller: stageRef.current,
    pin: true,
    scrub: true,
    end: () => `+=${wrap.offsetWidth}`,
  },
});
```

```html title="horizontal-gallery-markup.html"
<div class="flex w-[300%]">
  <div class="gsap-h-panel min-w-full">Design</div>
  <div class="gsap-h-panel min-w-full">Build</div>
  <div class="gsap-h-panel min-w-full">Ship</div>
</div>
```

  </DocsFileTabs>
</ComponentPreview>

Create ScrollTriggers **top-to-bottom** on the page, or set **`refreshPriority`** when order differs.
