Scroll Reveal

Animated

A block that wipes into view the first time it is scrolled to.

View Source

#Installation

npx @dinachi/cli@latest add scroll-reveal

#Usage

tsx
import { ScrollReveal } from "@/components/ui/scroll-reveal"
tsx
<ScrollReveal>
  <FeatureGrid />
</ScrollReveal>

#Examples

#Direction

The aperture opens against the travel, so the block appears to slide up through a shutter opening downwards. up is the default and the right one for anything read top to bottom.

DirectionContent travelsAperture opens from
upUpTop
downDownBottom
leftLeftRight
rightRightLeft

#When to use it

Only on content the reader has not seen yet. A page where everything reveals is a page that is slow to read, because every block withholds itself until the scroll catches up.

Use it forNot for
One hero block, one feature grid.Anything the reader returns to, or arrives at from a deep link. It is better off just being there.
A flourish the page survives without.Content whose absence would be a bug. The hidden state is a real style, so the block needs JS to become visible.
A single block.An actual list. Stagger List sequences from one trigger rather than one observer per item.

#Behaviour

  • It reveals once. repeat is off by default. Replaying an entrance on content already read makes the page feel like it is fighting the scroll.
  • margin holds the reveal back until the block is clear of the fold. A block shorter than that inset, sitting at the very bottom of the scroll range, can never clear the line. Pass "0px" for trailing content with nothing below it.
  • root must be an ancestor of the revealed content. Against an unrelated root the observer reports no intersection at all and the block stays hidden.

#Accessibility

  • Reduced motion keeps the fade and drops the wipe and the travel. The fade still signals that new content arrived, which is the part worth keeping.

#API Reference

PropTypeDefaultDescription
direction"up" | "down" | "left" | "right""up"Direction the content travels as it reveals. The aperture opens against the travel
distancenumber8Travel distance in px. The wipe is the gesture; the nudge only gives it a direction
durationnumber0.45Seconds. Front-loaded by the easing, so most of the travel lands in the first third
delaynumber0Seconds to wait after entering view
repeatbooleanfalseRe-run every time it re-enters view. Best left off: replaying an entrance on content already read is decoration
marginstring"0px 0px -100px 0px"Root margin for the viewport trigger. Pass "0px" for trailing content with nothing below it
amountnumber | "some" | "all""some"Fraction of the element that must be visible. A numeric amount is unreachable for a block taller than the root
rootRefObject<Element>Observe against a scrollable ancestor instead of the viewport. Must be an ancestor of the revealed content