Scroll story
BlockSections that change as you scroll.
pnpm dlx shadcn@latest add https://caliperui.site/r/scroll-story.json01
Write the change
Work in a branch. Every component ships with its states, its keyboard behaviour and its tests.
02
Check it everywhere
Light and dark, desktop and phone, motion on and off. The same checks run on every pull request.
03
Ship it calmly
A release is one button with a checklist behind it. If anything is in the way, it says exactly what.
When to use #
Use it for
- Walking through a product story.
Skip it when
- Short pages.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/scroll-story.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { ScrollStory } from "@/components/ui/scroll-story" const mock = (n: number, label: string) => ( <div className="grid w-full max-w-xs gap-2" aria-hidden="true"> <p className="text-xs uppercase tracking-wide text-muted-foreground">{label}</p> {[0.9, 0.6, 0.75].map((w, i) => <span key={i} className="block h-3 rounded-full" style={{ width: `${w * 100}%`, background: `color-mix(in srgb, var(--chart-${n}) ${70 - i * 18}%, var(--background))` }} />)} <span className="mt-2 block h-16 rounded-lg" style={{ background: `color-mix(in srgb, var(--chart-${n}) 22%, var(--background))` }} /> </div> ); export function ScrollStoryDemo() { return ( <div className="grid gap-3"> <ScrollStory label="How a release goes out" steps={[ { id: "s1", title: "Write the change", body: "Work in a branch. Every component ships with its states, its keyboard behaviour and its tests.", visual: mock(1, "Branch") }, { id: "s2", title: "Check it everywhere", body: "Light and dark, desktop and phone, motion on and off. The same checks run on every pull request.", visual: mock(2, "Checks") }, { id: "s3", title: "Ship it calmly", body: "A release is one button with a checklist behind it. If anything is in the way, it says exactly what.", visual: mock(4, "Release") }, ]} /> </div> ); }
API reference #
ScrollStory
component
Accessibility #
It is built on native elements and keeps aria-label, aria-hidden and aria-current in step with state.
Motion #
It checks prefers-reduced-motion itself and settles immediately instead of travelling. Every state is still reachable.