---
title: 'Pin & Scrub'
excerpt: 'Pin sections while scrolling and tie animation progress to scroll position.'
icon: 'ScrollText'
---

## Pinning a section

**Pin** freezes a trigger in the viewport while the user keeps scrolling through an artificial distance (`end: '+=200'`). Put motion on **children** inside the pin — transforming the pinned node itself fights ScrollTrigger’s pin transforms.

`pinSpacing: true` inserts spacer so the rest of the page does not jump under the pin. `scrub: 0.5` slightly smooths the linked animation.

## Pinned walkthrough

Scroll the stage: the analytics panel sticks, then releases after the pin distance. Content inside can still animate while the shell is pinned.

<ComponentPreview flush previewClassName="min-h-[320px]">
  <GsapScrollPin />

  <DocsFileTabs title="Scroll pin">

```tsx title="scroll-pin.tsx"
scrollTrigger: {
  trigger: panel,
  scroller: stageRef.current,
  start: 'top top',
  end: '+=200',
  pin: true,
  pinSpacing: true,
  scrub: 0.5,
}
```

```html title="scroll-pin-markup.html"
<section class="gsap-pin-panel h-[200px]">
  <div class="gsap-pin-inner flex h-full items-center justify-center rounded-lg border bg-card">
    <p>Analytics</p>
    <p>Pinned while scrolling</p>
  </div>
</section>
```

  </DocsFileTabs>
</ComponentPreview>

## ScrollTo section

**ScrollToPlugin** animates the scroller to a target (`y: '#section-b'`) instead of a hard jump. Pair with nav buttons for in-panel section jumps — same idea as page anchors, with easing.

Click A / B: the stage eases to that section with a small `offsetY` so headers are not flush against the edge.

<ComponentPreview flush previewClassName="min-h-[280px]">
  <GsapScrollToSection />

  <DocsFileTabs title="Scroll to">

```tsx title="scroll-to.tsx"
import { ScrollToPlugin } from 'gsap/ScrollToPlugin';
gsap.registerPlugin(ScrollToPlugin);

gsap.to(scroller, {
  duration: 0.8,
  scrollTo: { y: '#section-b', offsetY: 8 },
  ease: 'power2.inOut',
});
```

```html title="scroll-to-markup.html"
<div class="sticky top-0 flex gap-2">
  <button>Section A</button>
  <button>Section B</button>
</div>
<div id="sec-a" class="rounded-lg border bg-card p-6">Section A</div>
<div id="sec-b" class="rounded-lg border bg-card p-6">Section B</div>
```

  </DocsFileTabs>
</ComponentPreview>

Call **`ScrollTrigger.refresh()`** after layout changes (images, fonts, dynamic content). Viewport resize is debounced automatically.
