viewmotion

Astro

viewmotion (core)

Astro is a first-class citizen for viewmotion. The core package ships motion() and stagger() helpers that return attribute spreads — perfect for Astro’s template syntax.

Installation

npm install viewmotion

Initialization

Call initMotion() once in your layout. With Astro’s ClientRouter (ViewTransitions), use the astro:page-load event so animations re-trigger on every navigation:

<script>
  import { initMotion } from "viewmotion";

  document.addEventListener("astro:page-load", async () => {
    await initMotion();
  });
</script>

motion() helper

Use the spread syntax to add animation attributes to any element:

---
import { motion } from "viewmotion";
---

<h1 {...motion("fade-up")}>Hello</h1>

<!-- With options -->
<div {...motion("slide-left", { delay: 200 })}>Content</div>

stagger() helper

Apply stagger() to a container — each direct child with data-motion receives an automatic incremental delay based on step:

---
import { motion, stagger } from "viewmotion";
const features = ["Fast", "Lightweight", "Accessible"];
---

<div {...stagger({ step: 80 })}>
  {features.map((f) => (
    <div {...motion({ preset: "fade-up" })}>{f}</div>
  ))}
</div>

Tip

stagger() spreads a data-stagger attribute on the container. When initMotion() runs, it reads step and sets each child’s delay to index × step ms.

Full page example

---
import { motion, stagger } from "viewmotion";
import Layout from "../layouts/Layout.astro";

const cards = ["Card 1", "Card 2", "Card 3"];
---

<Layout title="Home">
  <section>
    <h1 {...motion("fade-up")}>Welcome</h1>
    <p {...motion("fade-up", { delay: 100 })}>
      A minimal reveal animation library.
    </p>

    <div {...stagger({ step: 80 })}>
      {cards.map((c) => (
        <div {...motion({ preset: "fade-up" })}>{c}</div>
      ))}
    </div>
  </section>
</Layout>

ViewTransitions support

When using Astro’s ClientRouter, animations re-trigger correctly on each navigation because initMotion() listens to astro:page-load. The observer is re-created on each page load, so new elements are picked up automatically.