Section Snap Pin
Section pinning plus snap-scroll choreography — full-height sections snap one by one to fill the viewport, content reveals and exits in order, with side navigation dots.
This is a WebberUI Pro component
Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.
npx shadcn@latest add "https://webberui.com/r/section-snap-pin.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<SectionSnapPin />
Installation
npx shadcn@latest add "https://webberui.com/r/section-snap-pin.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/section-snap-pin.
Usage
SectionSnapPin is itself a vertical snap scroll container, so give it a fixed height (for example h-[80vh] or h-screen). Put several SnapSection elements inside it, and inside each section wrap the elements you want choreographed in SnapReveal.
import {
SectionSnapPin,
SnapSection,
SnapReveal,
} from "@/components/ui/section-snap-pin";
<SectionSnapPin className="h-screen">
<SnapSection label="Overview" className="bg-neutral-950 text-white">
<SnapReveal order={0}>
<span className="text-xs tracking-widest uppercase">01</span>
</SnapReveal>
<SnapReveal order={1}>
<h2 className="text-4xl font-semibold">Snapping sections</h2>
</SnapReveal>
</SnapSection>
<SnapSection label="Choreography" className="bg-indigo-600 text-white">
<SnapReveal order={0} from="left">
<h2 className="text-4xl font-semibold">Revealed in order</h2>
</SnapReveal>
</SnapSection>
</SectionSnapPin>Props
SectionSnapPin
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | One or more SnapSection elements |
snap | "mandatory" | "proximity" | "mandatory" | Snap strength |
indicator | boolean | true | Whether to show the side section navigation dots |
indicatorPosition | "left" | "right" | "right" | Position of the navigation dots |
onActiveChange | (index: number) => void | — | Callback fired when the snapped section changes |
aria-label | string | "Section snap scrolling" | Accessible label for the scroll area |
className | string | — | The outermost container (set the fixed height here) |
SnapSection
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Section content, usually several SnapReveal elements |
label | string | — | Section name, used as the navigation dot tooltip and the accessible label |
align | "start" | "center" | "end" | "center" | Vertical alignment of the content within the section |
className | string | — | Additional styling (background, text color, and so on) |
SnapReveal
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The content to choreograph into view |
order | number | 0 | Reveal order; multiplied by stagger to get the delay |
from | "up" | "down" | "left" | "right" | "none" | "up" | Direction of the reveal offset |
distance | number | 24 | Reveal offset distance (px) |
stagger | number | 0.08 | Interval between order steps (seconds) |
duration | number | 0.6 | Duration of a single unit's animation (seconds) |
className | string | — | Additional styling |
How it works
SectionSnapPinachieves snapping with CSS Scroll Snap (snap-y+snap-mandatory/snap-proximity), leaving scroll performance to the browser's native implementation.- Each
SnapSectionuses anIntersectionObserver(with the scroll container as root) to decide whether it is more than 55% visible and therefore the primary section; that state is passed through context to the innerSnapRevealelements to trigger the reveal, with an exit when it leaves — so scrolling back in choreographs it again. - The thin rail beside the navigation dots fills in real time, tracking the container's scroll progress with
useScroll. - The scroll container's native scrollbar is hidden with styling; snapping and the navigation dots provide the sense of position instead.
Accessibility
- The scroll container carries
role="region",aria-label, andtabIndex, so it can be focused by keyboard and sections switched with↑/↓,PageUp/PageDown, andHome/End. - The navigation dots are native
<button>elements with anaria-label(taken from the sectionlabel) andaria-current; they work by keyboard and show a tooltip. - When the user has "reduce motion" enabled at the system level, smooth scrolling becomes an instant jump and
SnapRevealrenders its content statically with no reveal offset.
Scroll Timeline
A scroll-driven timeline where the growing line extends along the main axis and each node lights up and reveals its content as the line arrives.
Container Scroll 3d
A container that rotates in 3D as you scroll to reveal its content, flattening out from a tilted-back angle to push the view right up to the viewer.