Astro’s whole premise is shipping no JavaScript unless you ask for it, so wrapping content in a hydrated component just to animate it defeats the point. Here the markup stays a server component: mark elements with a data attribute, pass options as JSON, and call one init function from a single client script. One small script for the whole page, not an island per animation.
Data attribute + init call
svg-scroll-draw/astro — every sample below is written against the wrappers this package actually exports.
---
// No client directive — this stays a server component.
---
<div data-scroll-draw data-scroll-draw-options='{"easing":"ease-out","fade":true}'>
<svg viewBox="0 0 200 100">
<path d="M10 50 Q 100 10 190 50" stroke="#111" fill="none" />
</svg>
</div>
<script>
import { initScrollDraw } from 'svg-scroll-draw/astro';
initScrollDraw();
</script><script>
// initAll wires up draw, animate, counter and text in one pass —
// put it in your layout and every page gets it.
import { initAll } from 'svg-scroll-draw/astro';
initAll();
</script><h2 data-scroll-text data-scroll-text-options='{"split":"words","stagger":0.05}'>
Every API, one package.
</h2>
<span data-scroll-counter data-scroll-counter-options='{"to":48000}'>0</span>
<div data-scroll-animate data-scroll-animate-options='{"from":{"opacity":0,"y":24}}'>
Fades up on scroll.
</div>Worth knowing: Options are read from the JSON attribute, so they must be valid JSON — double-quoted keys, no trailing commas, no JS expressions. Single-quoting the attribute in your markup is the easiest way to keep the inner quotes valid.
10 KB gzipped for every API at once, and each one is a separate entry point — so a page that only reveals elements ships 3.9 KB, not the lot. The equivalent GSAP stack for the same work is 47.5 KB, which makes this 4.75× smaller. GSAP is free and considerably broader; if you need timelines, Draggable or Flip, use GSAP.
Measured 2026-08-14 at gzip level 9 against gsap 3.15.0 and svg-scroll-draw 2.10.0. Full comparison →
Add data-scroll-draw to any element, pass options via data-scroll-draw-options as JSON, and call initScrollDraw() from a plain <script> tag. Astro bundles that script but the component itself is never hydrated, so no framework runtime ships.
No. A client directive hydrates a framework component; this uses a plain script tag instead, so there is no island and no framework runtime in the bundle.
Yes. initAll() wires up draw, animate, counter and text in a single pass. Put it in your layout and every page is covered by one small script.