scrollAnimate in Vue 3,
Svelte, and Solid.js
svg-scroll-draw v2.3 ships first-class wrappers for all three frameworks. This guide covers every API — composables, actions, hooks, component wrappers — with copy-paste examples for real-world patterns.
1. Install
One package, all frameworks. Install once and import from the framework-specific subpath.
npm install svg-scroll-draw # or pnpm add svg-scroll-draw
Vue, Svelte, and Solid are all peer dependencies — they're already in your project. The wrappers tree-shake cleanly; only the code you import gets bundled.
2. Vue 3
All v2 APIs ship as composables that return a ref you bind with :ref. There are also ready-made component wrappers if you prefer that style.
scrollAnimate — fade + slide on scroll
<script setup>
import { useScrollAnimate } from 'svg-scroll-draw/vue';
const el = useScrollAnimate({
props: {
opacity: [0, 1],
transform: ['translateY(40px)', 'translateY(0)'],
},
easing: 'ease-out',
once: true,
});
</script>
<template>
<div :ref="el">
This fades and slides in as it scrolls into view.
</div>
</template>scrollText — split + stagger animate
<script setup>
import { useScrollText } from 'svg-scroll-draw/vue';
const headline = useScrollText({
split: 'words',
stagger: 0.05,
from: { opacity: 0, y: 24 },
once: true,
});
const subline = useScrollText({
split: 'chars',
stagger: 0.015,
from: { opacity: 0 },
once: true,
});
</script>
<template>
<h1 :ref="headline">Ship faster. Zero GSAP.</h1>
<p :ref="subline">Every character trickles in on scroll.</p>
</template>scrollCounter — animated numbers
<script setup>
import { useScrollCounter } from 'svg-scroll-draw/vue';
const users = useScrollCounter({
to: 50_000,
format: n => Math.round(n).toLocaleString() + '+',
easing: 'ease-out',
once: true,
});
</script>
<template>
<!-- Renders a <span> that counts 0 → 50,000+ on scroll -->
<span :ref="users" />Component wrappers
Prefer components over composables? All four v2 APIs have component wrappers too.
<script setup>
import { ScrollAnimate, ScrollText, ScrollCounter } from 'svg-scroll-draw/vue';
</script>
<template>
<!-- Wraps children in a <div> and animates -->
<ScrollAnimate :options="{ props: { opacity: [0,1] }, easing: 'ease-out', once: true }">
<MyCard />
</ScrollAnimate>
<!-- Renders a <p> tag by default (change with tag="h2") -->
<ScrollText :options="{ split: 'words', stagger: 0.05 }" tag="h2">
Animate on scroll.
</ScrollText>
<!-- Renders a <span> counter -->
<ScrollCounter
:to="1250000"
:format="n => '$' + Math.round(n).toLocaleString()"
easing="ease-out"
:once="true"
/>
</template>svg-scroll-draw/nuxt instead — it re-exports everything and includes a plugin factory for global component registration.3. Svelte
All v2 APIs are Svelte use: actions. The matching create* helpers give you access to the live instance for replay, pause, and seek.
scrollAnimate action
<script>
import { scrollAnimate } from 'svg-scroll-draw/svelte';
const opts = {
props: {
opacity: [0, 1],
transform: ['translateY(40px)', 'translateY(0)'],
},
easing: 'ease-out',
once: true,
};
</script>
<div use:scrollAnimate={opts}>
Fades and slides in on scroll.
</div>scrollTextAction — split text
<script>
import { scrollTextAction } from 'svg-scroll-draw/svelte';
</script>
<h1 use:scrollTextAction={{ split: 'words', stagger: 0.05, once: true }}>
Ship faster. Zero GSAP.
</h1>
<p use:scrollTextAction={{ split: 'chars', stagger: 0.015, from: { opacity: 0 }, once: true }}>
Every character trickles in on scroll.
</p>createScrollAnimate — with instance control
<script>
import { createScrollAnimate } from 'svg-scroll-draw/svelte';
const { action, getInstance } = createScrollAnimate({
props: { opacity: [0, 1], transform: ['translateY(40px)', 'translateY(0)'] },
easing: 'ease-out',
once: true,
});
</script>
<div use:action>...</div>
<button on:click={() => getInstance()?.replay()}>↺ Replay</button>The same create* pattern is available for all v2 actions:createScrollCounter,createScrollVideo,createScrollText.
4. Solid.js
All v2 APIs are SolidJS hooks that return a ref setter. The create* variants return { ref, getInstance } for imperative control.
useScrollAnimate
import { useScrollAnimate } from 'svg-scroll-draw/solid';
function Hero() {
const ref = useScrollAnimate({
props: {
opacity: [0, 1],
transform: ['translateY(40px)', 'translateY(0)'],
},
easing: 'ease-out',
once: true,
});
return <div ref={ref}>Fades and slides in on scroll.</div>;
}useScrollText
import { useScrollText } from 'svg-scroll-draw/solid';
function Headline() {
const headRef = useScrollText({
split: 'words',
stagger: 0.05,
from: { opacity: 0, y: 24 },
once: true,
});
return <h1 ref={headRef}>Ship faster. Zero GSAP.</h1>;
}createScrollAnimate — with instance access
import { createScrollAnimate } from 'svg-scroll-draw/solid';
function HeroSection() {
const { ref, getInstance } = createScrollAnimate({
props: { opacity: [0, 1], transform: ['translateY(40px)', 'translateY(0)'] },
easing: 'ease-out',
once: true,
});
return (
<>
<div ref={ref}>...</div>
<button onClick={() => getInstance()?.replay()}>↺ Replay</button>
</>
);
}5. Real-world patterns
Staggered card grid (Vue)
Use v-for with independent composable calls — one instance per card, each with a trigger offset for a natural cascade:
<script setup>
import { useScrollAnimate } from 'svg-scroll-draw/vue';
import { ref as vueRef, onMounted } from 'vue';
import { scrollAnimate } from 'svg-scroll-draw';
const cardRefs = vueRef([]);
onMounted(() => {
cardRefs.value.forEach((el, i) => {
scrollAnimate(el, {
props: {
opacity: [0, 1],
transform: ['translateY(32px)', 'translateY(0)'],
},
trigger: {
start: `top ${90 - i * 4}%`,
end: `top ${55 - i * 4}%`,
},
easing: 'ease-out',
once: true,
});
});
});
</script>
<template>
<div class="grid">
<div v-for="(card, i) in cards" :key="i" :ref="el => cardRefs[i] = el">
{{ card.title }}
</div>
</div>
</template>Marketing headline (Svelte)
<script>
import { scrollTextAction } from 'svg-scroll-draw/svelte';
import { scrollAnimate } from 'svg-scroll-draw/svelte';
const eyebrowOpts = {
props: { opacity: [0, 1], transform: ['translateY(10px)', 'translateY(0)'] },
trigger: { start: 'top 90%', end: 'top 68%' },
easing: 'ease-out', once: true,
};
</script>
<div use:scrollAnimate={eyebrowOpts}>
<span class="badge">New in v2</span>
</div>
<h1 use:scrollTextAction={{ split: 'words', stagger: 0.07, from: { opacity: 0, y: 36 }, once: true }}>
Scroll animations without GSAP.
</h1>
<p use:scrollTextAction={{ split: 'chars', stagger: 0.012, from: { opacity: 0 }, once: true }}>
Vue · Svelte · Solid · React · ~9 KB
</p>6. Nuxt & Astro
Nuxt 3
Import from svg-scroll-draw/nuxt — it re-exports all v2 composables and components, and provides a plugin for global registration:
import { createScrollDrawPlugin } from 'svg-scroll-draw/nuxt';
export default defineNuxtPlugin((nuxtApp) => {
// Registers <ScrollDraw>, <ScrollAnimate>, <ScrollCounter>,
// <ScrollVideo>, <ScrollText> globally — no per-component imports.
nuxtApp.vueApp.use(createScrollDrawPlugin());
});Astro
Use data-attributes for zero-import server components. initScrollAnimate and initScrollText are new in v2.3:
---
// No imports needed server-side
---
<h1
data-scroll-text
data-scroll-text-options='{"split":"words","stagger":0.05,"once":true}'
>
Animate on scroll.
</h1>
<div
data-scroll-animate
data-scroll-animate-options='{"props":{"opacity":[0,1],"transform":["translateY(40px)","translateY(0)"]},"easing":"ease-out","once":true}'
>
Fades and slides in.
</div>
<script>
import { initAll } from 'svg-scroll-draw/astro';
// Initialises scrollDraw, scrollAnimate, scrollText, scrollCounter in one call
initAll();
</script>Summary
| Framework | Pattern | Import |
|---|---|---|
| Vue 3 | useScrollAnimate(options) → ref | svg-scroll-draw/vue |
| Vue 3 | <ScrollAnimate :options="..."> | svg-scroll-draw/vue |
| Svelte | use:scrollAnimate={opts} | svg-scroll-draw/svelte |
| Svelte | createScrollAnimate → { action, getInstance } | svg-scroll-draw/svelte |
| Solid | useScrollAnimate(options) → ref setter | svg-scroll-draw/solid |
| Solid | createScrollAnimate → { ref, getInstance } | svg-scroll-draw/solid |
| Nuxt | Same as Vue + plugin factory | svg-scroll-draw/nuxt |
| Astro | data-scroll-animate + initScrollAnimate() | svg-scroll-draw/astro |