Skip to content

boccdotdev/data-reveal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@boccdotdev/data-reveal

Declarative, scroll-triggered reveal animations driven by HTML data- attributes. Powered by GSAP + ScrollTrigger.

  • Code-split — each animation type loads on demand. A page that only uses fade never downloads the split code (or its SplitText plugin).
  • Zero side effects on import — nothing runs, and no GSAP is loaded, until you call init().
  • Respects prefers-reduced-motion — elements snap to their final state instead of animating.

Install

npm install @boccdotdev/data-reveal gsap

gsap is a peer dependency (>=3.13.0) — you install it yourself so the package shares your single GSAP instance. GSAP 3.13+ ships ScrollTrigger and SplitText for free; no Club membership required.

Quick start

import { createReveal } from "@boccdotdev/data-reveal";

const reveal = createReveal();
await reveal.init();          // scan the document, load only the types in use
<h2 data-reveal="split" data-reveal-split="words">Animated headline</h2>
<div data-reveal="fade" data-reveal-direction="left">Fades in from the left</div>
<span data-reveal="counter" data-reveal-to="1200" data-reveal-separator=",">0</span>

That's it. Add a data-reveal attribute to any element and it animates as it scrolls into view.

How loading works

init() scans the container for [data-reveal], collects the set of types present, then dynamically import()s only those modules. Your bundler (Vite, webpack, etc.) splits each type into its own chunk, so the browser fetches code for an animation only when a page actually uses it. GSAP itself rides along in those chunks — a page with no reveals loads no GSAP.

Because loading is dynamic, init() is async. await it (or .then()) if you need to run code after reveals are set up.

Minimal builds (manual registration)

Auto mode is convenient, but to dynamically load any type on demand it has to reference every type — so your bundler emits a chunk file for all of them, even ones your site never uses. They're never downloaded unless present on a page, but the files still sit in your build output.

If you want only the types you use to exist in your build at all, import the /manual entry and register types explicitly. It has no reference to the auto-loader, so unused type modules (and their GSAP plugins) are never bundled:

import { createReveal } from "@boccdotdev/data-reveal/manual";
import { fade } from "@boccdotdev/data-reveal/fade";
import { scale } from "@boccdotdev/data-reveal/scale";

const reveal = createReveal({ types: [fade, scale] });
await reveal.init();

Each type is importable from its own subpath: @boccdotdev/data-reveal/{fade,scale,split,batch,blur,clip,rotate,slide,counter,parallax}. The HTML API is identical — data-reveal="fade" still works; you've just told the bundler which types are in play. A data-reveal type you didn't register is silently skipped.

The returned instance is the same as auto mode — init, refresh, destroy all behave identically. Choose auto for zero-config convenience, manual when build size matters.

API

const reveal = createReveal();

await reveal.init();              // scan document
await reveal.init(myContainer);   // scan a subtree only (any ParentNode)

reveal.refresh();                 // recompute all ScrollTrigger positions

reveal.destroy();                 // kill everything, revert SplitText, forget all elements
reveal.destroy(myContainer);      // kill + forget only reveals on/inside myContainer

init() is idempotent — already-initialized elements are skipped, so you can safely call it again as new content is added (e.g. infinite scroll).

refresh()

Recomputes every ScrollTrigger's start/end positions. ScrollTrigger already refreshes on window resize and load, but a JavaScript-driven layout change doesn't fire that — so call refresh() after toggling a grid's column count, opening an accordion, or when fonts/images finish loading and shift the page. Calls are coalesced to one refresh per frame, so it's cheap to call repeatedly.

destroy(container?)

With no argument, kills all tweens + ScrollTriggers, reverts SplitText, and forgets every element — a later init() re-runs the whole page. Pass a container to tear down only the reveals on or inside it; those elements are forgotten too, so re-adding content there and calling init() re-animates just that subtree. contains works on detached nodes, so you can pass a subtree you're about to remove. Use the scoped form for SPA partial swaps, the bare form for a full route change.

Animation types

All types accept these shared attributes:

Attribute Default Notes
data-reveal-duration varies Seconds
data-reveal-delay 0 Seconds
data-reveal-start top 85% ScrollTrigger start position
data-reveal-reverse off Add it to play the animation out again when scrolling back up past start. Default is play-once. (parallax is always bidirectional and ignores this.)

fade

Fade + translate in.

Attribute Default Values
data-reveal-direction up up down left right
data-reveal-distance 20 px

scale

Fade + scale up.

Attribute Default Notes
data-reveal-from 0.92 Starting scale

split

Per-character/word/line text reveal (uses SplitText).

Attribute Default Values
data-reveal-split chars chars words lines
data-reveal-stagger 0.02 Seconds between units

batch

Staggered reveal of many children as they enter together. Targets elements marked data-reveal-item, or falls back to direct children.

Attribute Default Notes
data-reveal-stagger 0.06 Seconds
data-reveal-distance 20 px
<ul data-reveal="batch">
  <li data-reveal-item>One</li>
  <li data-reveal-item>Two</li>
</ul>

blur

Fade in from a blur.

Attribute Default Notes
data-reveal-blur 12 Starting blur in px

clip

clip-path wipe reveal.

Attribute Default Values
data-reveal-direction up up down left right (wipe direction)

rotate

3D rotate in.

Attribute Default Values
data-reveal-axis x x y z
data-reveal-rotate 90 Degrees

slide

Slide in from fully off the element's own box.

Attribute Default Values
data-reveal-direction up up down left right

counter

Count a number up as it enters view. Reads the target from data-reveal-to, or the element's text content.

Attribute Default Notes
data-reveal-to element text Target number
data-reveal-from 0 Starting number
data-reveal-decimals 0 Decimal places
data-reveal-separator Thousands separator, e.g. ,
data-reveal-prefix e.g. $
data-reveal-suffix e.g. %

parallax

Continuous, scroll-linked motion (scrubbed — not a one-shot reveal). Disabled under reduced motion.

Attribute Default Notes
data-reveal-speed 0.3 Higher = more movement
data-reveal-start top bottom ScrollTrigger start
data-reveal-end bottom top ScrollTrigger end

License

MIT

About

Scroll-triggered reveal animations driven by data-reveal attributes. GSAP-powered, code-split, zero-config.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors