Vue 3Vue 3 · Vite · Nuxt 3

Vue 3 scroll animations.
Composables and components.

Vue gets real wrappers here, not a vanilla escape hatch: a component for the common case and a composable when you need the element ref yourself. Both ship in the same package — there is no separate Vue build — and both tear down on unmount, so nothing leaks across route changes.

Composable + component

Quick start.

svg-scroll-draw/vue — every sample below is written against the wrappers this package actually exports.

The composable — you own the ref

Hero.vue
<script setup>
import { useScrollDraw } from 'svg-scroll-draw/vue';

// Returns a ref — bind it to the element wrapping your SVG.
const container = useScrollDraw({
  easing: 'ease-out',
  speed: 1.2,
  fade: true,
});
</script>

<template>
  <div ref="container">
    <svg viewBox="0 0 200 100">
      <path d="M10 50 Q 100 10 190 50" stroke="#111" fill="none" />
    </svg>
  </div>
</template>

The component — no ref wiring

Logo.vue
<script setup>
import { ScrollDraw } from 'svg-scroll-draw/vue';
</script>

<template>
  <ScrollDraw :easing="'ease-out'" :speed="1.2" once>
    <svg viewBox="0 0 200 100">
      <path d="M10 50 Q 100 10 190 50" stroke="#111" fill="none" />
    </svg>
  </ScrollDraw>
</template>

Reveal, counters and text

Features.vue
<script setup>
import { useScrollAnimate, useScrollCounter, useScrollText } from 'svg-scroll-draw/vue';

const card    = useScrollAnimate({ from: { opacity: 0, y: 24 } });
const revenue = useScrollCounter({ to: 48000, format: n => `$${n.toLocaleString()}` });
const heading = useScrollText({ split: 'words', stagger: 0.05 });
</script>

<template>
  <h2 ref="heading">Every API, one package.</h2>
  <div ref="card"><span ref="revenue">0</span></div>
</template>

Worth knowing: The composable returns the ref rather than taking one, so you never have to guard against a null element on first render — the engine only starts after onMounted.

Size.

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 →

Vue 3 questions.

How do I animate on scroll in Vue 3?

Install svg-scroll-draw and import either the ScrollDraw component or the useScrollDraw composable from svg-scroll-draw/vue. The composable returns a template ref you bind to the element wrapping your SVG; the animation is driven by scroll position and cleans up automatically on unmount.

Does it work with Nuxt 3 and SSR?

Yes. The engine only initialises in onMounted, so nothing touches the DOM during server rendering. Nuxt users can import from svg-scroll-draw/nuxt, which re-exports every Vue composable and component plus a plugin for global registration.

Is there a Vue alternative to GSAP ScrollTrigger?

svg-scroll-draw covers the common ScrollTrigger cases — scroll-driven animation, pin, snap, parallax, text split, counters and video scrub — at 10.0 KB for every API versus 47.5 KB for GSAP core plus ScrollTrigger plus DrawSVG. GSAP is broader; if you need timelines, Draggable or Flip, use GSAP.