Scrollytelling
Also called scroll storytelling
A storytelling layout where a pinned graphic changes step by step as the reader scrolls through short blocks of text beside it.
import { useState } from 'react';
import { motion } from 'motion/react';
const releases = { 2021: 40, 2022: 65, 2023: 90, 2024: 140 };
const MAX = 140;
const steps = [
'In 2021 the team shipped 40 releases, about one every nine days.',
'Automated tests in 2022 pushed that to 65.',
'Preview deploys made every pull request testable: 90 releases in 2023.',
'By 2024 the team shipped 140 times, nearly every other day.'
];
export function ReleaseStory() {
const [active, setActive] = useState(0);
return (
<section className='grid gap-8 md:grid-cols-2'>
{/* Pinned to the top half on phones, beside the text from md up. */}
<div className='sticky top-0 z-10 flex h-[50vh] gap-4 bg-background p-6 md:top-[15vh] md:order-last md:h-[70vh]'>
{Object.entries(releases).map(([year, count], index) => (
<div
key={year}
className='flex flex-1 flex-col gap-2 text-center text-sm'
>
<div className='flex flex-1 items-end'>
<div
className={`w-full origin-bottom rounded-t-lg transition-[scale,background-color] duration-400 ease-out motion-reduce:transition-none ${index === active ? 'bg-blue-600' : 'bg-muted'}`}
style={{
height: `${(count / MAX) * 100}%`,
scale: index <= active ? '1 1' : '1 0'
}}
/>
</div>
{year}
</div>
))}
</div>
<div>
{steps.map((text, index) => (
<motion.p
key={text}
// A thin band across the middle of the viewport picks the active step.
viewport={{ margin: '-45% 0px -45% 0px' }}
onViewportEnter={() => setActive(index)}
className='flex min-h-[70vh] items-center text-lg'
>
{text}
</motion.p>
))}
</div>
</section>
);
}Build a scrollytelling section: on the left, four short text steps, each about 70vh tall; on the right, a bar chart with position: sticky; top: 15vh. When a step crosses the middle of the viewport, update the chart to that step’s data with a 400ms ease-out transition and highlight the matching bar. On screens under 768px, pin the chart to the top half of the screen, and skip the transitions when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Scrollytelling?
Scrollytelling pairs a sticky visual, such as a chart, map, or product shot, with a column of short text steps. As each step scrolls into the middle of the screen, the visual updates to match it: a new bar appears, the map zooms in, a feature lights up. News sites use it for data stories, and product pages use it to walk through features.
The visual stays in place with position: sticky, and each step is detected with IntersectionObserver or a scroll progress value. Switch states when a step crosses the middle of the viewport, and animate between them so the reader can see what changed.
Keep steps short and let readers scroll at their own pace, without taking over the scroll speed. On small screens, give the visual the top half of the screen or place it above each step, and make sure the story still reads in order with animations turned off.
Often confused with
- Scroll pinning
- Scroll pinning holds one section still while its own content animates. Scrollytelling keeps a visual in place beside text steps that tell it what to show.
Related terms
All termsScroll pinning
A scroll effect that holds a section in place while its content animates through several states, then releases it to scroll away.
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 reveal
An animation that fades or slides content into place as it scrolls into view, so each section appears just as the reader reaches it.
Purposeful animation
Animation used only where it helps people notice a change, follow where something went, or understand what just happened.
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.