Scroll pinning
Also called pinned section or sticky section
A scroll effect that holds a section in place while its content animates through several states, then releases it to scroll away.
import { useRef } from 'react';
import {
motion,
useReducedMotion,
useScroll,
useTransform
} from 'motion/react';
const steps = [
{ title: 'Describe', text: 'Tell the agent what you want to build.' },
{ title: 'Preview', text: 'Watch the app take shape as it builds.' },
{ title: 'Publish', text: 'Put it online with one click.' }
];
export function HowItWorks() {
const track = useRef<HTMLDivElement>(null);
const still = useReducedMotion();
// 0 when the track's top reaches the viewport top, 1 when its bottom reaches the viewport bottom.
const { scrollYProgress } = useScroll({
target: track,
offset: ['start start', 'end end']
});
// Each card slides up into place during its third of the scroll.
const cardY = [
useTransform(scrollYProgress, [0, 1 / 3], ['100vh', '0vh']),
useTransform(scrollYProgress, [1 / 3, 2 / 3], ['100vh', '0vh']),
useTransform(scrollYProgress, [2 / 3, 1], ['100vh', '0vh'])
];
return (
// 300vh of track gives the pinned 100vh section two extra screens of scroll to animate with.
// With reduced motion the track is only as tall as the section, so nothing pins.
<div ref={track} className={still ? 'relative' : 'relative h-[300vh]'}>
<section className='sticky top-0 flex h-screen items-center justify-center gap-4 overflow-hidden'>
{steps.map((step, index) => (
<motion.article
key={step.title}
style={still ? undefined : { y: cardY[index] }}
className='w-56 rounded-2xl border bg-background p-6 shadow-sm'
>
<h3 className='font-semibold'>{step.title}</h3>
<p className='mt-1 text-sm text-muted-foreground'>{step.text}</p>
</motion.article>
))}
{still ? null : (
<motion.div
style={{ scaleX: scrollYProgress }}
className='absolute inset-x-0 bottom-0 h-1 origin-left bg-blue-600'
/>
)}
</section>
</div>
);
}Pin the "How it works" section: wrap it in a container 300vh tall and give the section position: sticky; top: 0; height: 100vh. As the reader scrolls through the wrapper, slide the three step cards up into place one after another, each during its third of the scroll, and show a thin progress bar at the bottom. When prefers-reduced-motion is set, show all three cards without pinning.
Paste into Layerwise or any AI coding tool.
What is Scroll pinning?
With scroll pinning, a section reaches the top of the screen and stops moving while the reader keeps scrolling. That extra scroll distance drives an animation inside it, such as cards stacking up, a phone screen changing, or a headline building word by word. When the animation finishes, the section lets go and the page carries on.
The usual setup is a tall wrapper, say three screens high, holding a child with position: sticky; top: 0 that is one screen tall. Scroll progress through the wrapper, from 0 to 1, drives the animation. GSAP’s ScrollTrigger calls this pin; in Motion you pass the wrapper to useScroll as its target and map the progress with useTransform.
Pin sparingly: a section that eats several screens of scrolling can make the page feel stuck. Show progress inside the pinned area, keep the pinned distance short, and check that the content still makes sense on small screens and with reduced motion.
Often confused with
- Sticky header
- A sticky header stays visible for the whole page. A pinned section holds still only while its own animation plays, then scrolls away.
- Scrollytelling
- Scrollytelling keeps a visual in place beside text steps that change it. Scroll pinning holds a whole section still while its content animates.
Related terms
All termsScrollytelling
A storytelling layout where a pinned graphic changes step by step as the reader scrolls through short blocks of text beside it.
Horizontal scroll section
A pinned section where scrolling down moves a row of cards sideways, turning vertical scrolling into horizontal movement.
Scroll-driven animation
An animation whose progress is tied directly to the scroll position, so it moves forward as you scroll down and rewinds as you scroll up.
Scroll progress bar
A thin bar at the top of a page that fills from left to right as the reader scrolls, showing how much of the article is left.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.