Motion UIComponentsComponent

Scroll zoom reveal

A zoomed, tilted screenshot that settles crisp and flat as it scrolls into view.

npx shadcn@latest add @motion/scroll-zoom-reveal

API reference

Components

<ScrollZoomReveal />

The scroll-driven zoom/tilt/fade/unblur reveal. Wrap your content; it settles crisp as it rises through the viewport. Transform and opacity are split onto SEPARATE nodes on purpose: a single style object mixing transform MotionValues (scale/rotateX/y) with an opacity MotionValue freezes the opacity at its mount value (the transform channel keeps animating, opacity does not), so giving opacity its own transform-free node keeps it a live scroll-linked value.

startScale?

number = 1.45

The scale the content starts at before settling to 1 (a clear zoom-in that resolves as it rises). Default 1.45.

startTilt?

number = 22

The forward tilt in degrees the content starts at before settling flat (a rotateX leaning the top away from the viewer, anchored on the bottom edge). Default 22.

startOpacity?

number = 0.35

The opacity the content starts at before settling to fully opaque. Default 0.35.

softenPx?

number = 3

The blur radius in pixels the content starts softened by; it clears well before the settle point. 0 disables the blur entirely (the crisp path animates transform + opacity alone). Default 3.

settleAt?

number = 1

Where in the content's viewport passage the settle completes, as a fraction of the scroll window from rest (~55% viewport) to settle (~22% viewport). 0 = top edge at rest, 1 = top edge at the settle line. The zoom, tilt, fade and unblur all reach their resolved state by here. Default 1.

className?

string

Merged onto the shot (the transformed frame). Size and style the revealed frame here - cap its width, round its corners, add its shadow (e.g. mx-auto max-w-5xl rounded-lg shadow-2xl). The component owns only relative w-full origin-bottom (the bottom-anchored tilt origin is load-bearing).

children?

ReactNode

The content to reveal - a coded dashboard, a screenshot <img>, any frame. It settles as a single visual; give it its own accessible name (a labelled role="img" wrapper) if it is decorative chrome.