viewmotion

Quick start

Get your first scroll-reveal animation running in under a minute.

1. Import styles and initialize

Import the CSS file that contains the keyframes and the initMotion() function:

import "viewmotion/styles.css";
import { initMotion } from "viewmotion";

await initMotion();

2. Add data attributes to elements

Add a data-motion attribute with a JSON configuration object:

<h1 data-motion='{"preset":"fade-up"}'>Hello world</h1>

<p data-motion='{"preset":"fade-up","delay":200,"duration":600}'>
  Animates with a 200ms delay
</p>

3. That’s it!

Elements will animate automatically as they scroll into view. The observer runs once per element — after the animation triggers, the element is unobserved.

Tip

In any environment that supports object spread on elements — JSX (React, Solid, Preact), Astro templates, Vue JSX — you can use the motion() helper to avoid hand-writing JSON strings:

import { motion } from "viewmotion";

<h1 {...motion({ preset: "fade-up" })}>Hello world</h1>;

Framework adapter packages like viewmotion-react or viewmotion-vue wrap this pattern with ergonomic hooks and directives. See the framework adapters docs.

Full example

Here’s a complete HTML page using a bundler (Vite, Webpack, Parcel, etc.). With a bundler, import the CSS directly in your JS entry point — no <link> tag needed.

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 data-motion='{"preset":"fade-up"}'>Hello world</h1>

    <div data-stagger='{"delay":100}'>
      <div data-motion='{"preset":"fade-up"}'>Card 1</div>
      <div data-motion='{"preset":"fade-up"}'>Card 2</div>
      <div data-motion='{"preset":"fade-up"}'>Card 3</div>
    </div>

    <script type="module">
      import "viewmotion/styles.css";
      import { initMotion } from "viewmotion";
      await initMotion();
    </script>
  </body>
</html>

No bundler?

Use a CDN link instead and remove the import "viewmotion/styles.css" line from your script:

<link
  rel="stylesheet"
  href="https://unpkg.com/viewmotion@0.1.1/dist/styles.css"
/>

Common pitfalls

CSS not imported

Animations won’t work if viewmotion/styles.css is missing. It contains all the @keyframes definitions. Always import it before calling initMotion().

initMotion() called before DOM is ready

Call initMotion() after the DOM has parsed. In a plain HTML page, place the <script> tag at the end of <body> or use a DOMContentLoaded listener. In frameworks, use the appropriate lifecycle hook — useEffect in React, onMount in Svelte, onMounted in Vue.

registerPreset() called after initMotion()

Custom presets must be registered before initMotion() runs. Calling registerPreset() afterwards has no effect on elements already observed.