ScrollReveal Staggered Feature Grid — reset: false Explained

ScrollReveal Staggered Feature Grid · Scroll · Plain HTML, CSS & JS · Live preview

What's included

Features

Single reveal() call
One selector and one options object animate the entire grid — no per-card JS.
DOM-order stagger
interval delays each match by its position in the DOM, which lines up with the visual grid order.
Explicit reset: false
The one-time-reveal behavior is set and commented deliberately, not left as an implicit default.
Combined translate + fade
origin/distance and opacity animate together as one CSS transition.
Confident easing curve
A cubic-bezier ease-in-out gives each card a settled, non-linear motion.
Responsive column collapse
The grid drops to a single column under 680px without touching the reveal config.
No layout shift on reveal
Only opacity and transform animate, so revealing cards never reflow the grid.
Config-only customization
Every visual property of the effect is one options object, easy to retune without touching structure.

About this UI Snippet

ScrollReveal Staggered Feature Grid — Interval Stagger and reset: false, Explained

Screenshot of the ScrollReveal Staggered Feature Grid snippet rendered live

This is the simplest possible ScrollReveal setup — one selector, one .reveal() call — and it's worth studying precisely *because* it's simple: almost every visual decision in it is one configuration option, and getting those options right (rather than reaching for custom JS) is the actual skill.

The whole animation is six options

js sr.reveal('.sfg-card', { origin: 'bottom', distance: '40px', duration: 650, easing: 'cubic-bezier(0.5, 0, 0, 1)', interval: 110, opacity: 0 });

origin: 'bottom' plus distance: '40px' means each card starts 40px below its resting position; opacity: 0 adds a fade on top of that translation (ScrollReveal combines them into one CSS transition automatically). duration and the cubic-bezier easing control the individual card's motion curve — this particular bezier, (0.5, 0, 0, 1), is a strong ease-in-out that starts and ends with near-zero velocity, giving the card a smooth, confident settle rather than a linear slide.

interval is why six cards read as one grid, not six separate pops

interval: 110 is the option doing the "staggered" work: it delays each subsequent match in DOM order by 110ms relative to the one before it. Because the six cards are laid out left-to-right, top-to-bottom in a 3-column CSS grid, the stagger visually reads as a wave sweeping across each row — row 1's three cards cascade left to right, then row 2 picks up right where row 1 left off. This is a side effect of DOM order matching visual order, not something the grid explicitly encodes; reordering the cards in HTML without reordering them visually (e.g. via CSS order) would make the stagger direction disconnect from what the eye sees.

reset: false, made explicit rather than left as a default

ScrollReveal's reset option defaults to false, so this snippet technically didn't need to set it — but it does so explicitly and comments why, because the choice is easy to get backwards. With reset: false, once a card has revealed, ScrollReveal detaches its observer for that element; scrolling back up and down again does nothing further to it. With reset: true (used deliberately in the companion hero text reset snippet), the element re-hides every time it exits the viewport and re-plays every time it re-enters — appropriate for a hero someone lands on repeatedly, actively wrong for a feature grid buried mid-page that a user might scroll past several times while reading; re-triggering the same six-card cascade on every pass would feel like the page is stuttering rather than delighting.

Reusing it

The entire visual identity of this pattern — direction, distance, stagger speed, easing — lives in one options object. Swap origin: 'bottom' for 'left' to change the sweep axis, or drop interval to 0 for cards that reveal in unison instead of cascading.

Step by step

How to Use

  1. 1
    Add the ScrollReveal CDNInclude the scrollreveal UMD build from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSA 3-column, 6-card feature grid renders with all cards initially invisible.
  3. 3
    Scroll the grid into viewCards fade up from the bottom, cascading left to right, row by row, 110ms apart.
  4. 4
    Scroll away and backThe grid does not replay — reset: false means each card reveals exactly once.
  5. 5
    Tune the stagger feelRaise interval for a slower cascade, or set it to 0 for all cards revealing together.
  6. 6
    Add more cardsAppend another .sfg-card element — the single reveal() selector picks it up automatically.

Real-world uses

Common Use Cases

SaaS why-choose-us sections
Cascade a three-column feature grid in from the bottom with one selector and one reveal() call.
Portfolio skill grids
Stagger competency or service cards, with interval delaying each match by its position in the DOM.
Changelog highlight cards
Draw attention to release highlights, with reset: false set deliberately so the reveal happens only once.
Team and testimonial grids
Apply to any repeated card layout such as teams or testimonials, combining translate and fade into a single CSS transition.
Pricing included-features lists and defaults learning
Cascade the included features beneath a plan, and use it as a minimal reference for how few ScrollReveal options are needed.

Got questions?

Frequently Asked Questions

interval delays each matched element by its position in DOM order, and because the six cards are written in the HTML in the same left-to-right, top-to-bottom order they appear in the 3-column grid, the delay sequence lines up with the visual sweep. It is a side effect of DOM order matching visual order, not something the grid layout enforces.

With reset: false, ScrollReveal reveals each element once and then stops observing it — scrolling it out of view and back in does nothing further. With reset: true, it would re-hide the element every time it exits the viewport and animate it again every time it re-enters, which this snippet deliberately avoids so a feature grid a user scrolls past multiple times doesn't replay every pass.

It is the default, but setting it explicitly and commenting why documents the decision as intentional rather than incidental — someone reading the code later (including future you) shouldn't have to know ScrollReveal's default to understand that replay-on-rescroll was considered and rejected for this component.

Set interval to 0, or omit it entirely — with no interval, every matched card animates on the same timer relative to when it individually crosses the visibility threshold, so a grid fully inside the viewport at once would appear to reveal in unison.

A pure translate without opacity can look like the card was always there but just moving, especially with a short distance; a pure opacity fade with no motion can feel flat. Combining a modest 40px slide with a fade gives the reveal a sense of arrival without being a dramatic slide-in.

No — ScrollReveal animates transform (for the origin/distance translation) and opacity, both of which are compositor-only properties that never trigger layout or paint of surrounding elements, so the grid and page around it stay perfectly stable while cards animate in.

Build with AI

Build, Understand, Optimize, and Extend It With AI

This snippet is intentionally minimal, which makes it a good place to interrogate defaults rather than custom logic. Paste it into an AI assistant like Claude and ask it to explain precisely what reset: false changes about ScrollReveal's internal IntersectionObserver usage compared to reset: true, and why a feature grid is a better candidate for reset: false than a hero section is (the companion hero-text-reset snippet makes the opposite choice deliberately — worth comparing the two). Then ask what would happen visually if the six cards were reordered in the DOM without changing their visual grid position — the stagger direction would no longer match the sweep the eye sees. For extension, ask it to make the stagger interval scale dynamically with the number of cards, add a subtle scale transform alongside the existing translate/fade, or convert the single reveal() call into per-row reveal() calls with independent origins for a criss-cross effect.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "staggered feature grid" using ScrollReveal.js (v4, from a CDN) in plain HTML, CSS, and JavaScript.

Requirements:
- A 3-column responsive CSS grid (collapsing to 1 column below 680px) of 6 feature cards, each with an icon, a bold title, and a short description, styled as a rounded, bordered, shadowed card on a dark background.
- Reveal the entire grid with a SINGLE ScrollReveal reveal() call targeting all .sfg-card elements — no per-card JavaScript loop.
- The reveal config must use origin: 'bottom', a distance around 40px, opacity: 0, a cubic-bezier ease-in-out easing curve, and an interval (around 110ms) so cards stagger in DOM order — which, because the cards are written in the same order they appear visually in the grid, produces a left-to-right, row-by-row cascade.
- Explicitly set reset: false when constructing the ScrollReveal instance, and add a code comment explaining that this is a deliberate design choice for a feature grid (which a user might scroll past multiple times while reading a page) as opposed to a hero section a user usually only sees once per visit, where replaying the reveal (reset: true) is more appropriate.
- Make the page tall enough (e.g. min-height: 150vh on body) that the grid starts below the fold, so the reveal-on-scroll behavior is actually visible on load.
- Include a small caption below the grid noting that scrolling away and back does not replay the animation, as a visible demonstration of reset: false.
- Style it as a dark theme with a green accent color, soft shadows, and generous card padding.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

Requires
<div class="sfg-stage">
  <div class="sfg-head">
    <span class="sfg-tag">scrollreveal · reset: false</span>
    <h2>Built for Scale</h2>
    <p>Scroll down — each card reveals once, from the bottom, staggered across the grid.</p>
  </div>
  <div class="sfg-grid">
    <div class="sfg-card"><div class="sfg-ico">⚡</div><h3>Instant Deploys</h3><p>Push to main, live in under 10 seconds.</p></div>
    <div class="sfg-card"><div class="sfg-ico">🔐</div><h3>Zero-Trust Auth</h3><p>Every request verified, nothing implicitly trusted.</p></div>
    <div class="sfg-card"><div class="sfg-ico">📦</div><h3>Edge Caching</h3><p>Static and dynamic content cached at 40+ PoPs.</p></div>
    <div class="sfg-card"><div class="sfg-ico">🧮</div><h3>Usage Analytics</h3><p>Per-endpoint cost and latency, out of the box.</p></div>
    <div class="sfg-card"><div class="sfg-ico">🔄</div><h3>Auto Rollback</h3><p>Bad deploys revert themselves within 30 seconds.</p></div>
    <div class="sfg-card"><div class="sfg-ico">🧩</div><h3>Plugin API</h3><p>Extend the pipeline without forking the core.</p></div>
  </div>
  <p class="sfg-note">Scroll back up, then down again — the grid does <strong>not</strong> replay. That's intentional.</p>
</div>