SvelteSvelte 4 · 5 · SvelteKit

Svelte scroll animations.
Actions, not wrappers.

Svelte actions are exactly the right primitive for scroll animation: attach behaviour to a node you already have, with no wrapper element and no extra component in the tree. use:scrollDraw is a one-line addition to markup you have already written, and Svelte handles teardown through the action lifecycle.

Action

Quick start.

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

The action — one attribute

Hero.svelte
<script>
  import { scrollDraw } from 'svg-scroll-draw/svelte';
</script>

<div use:scrollDraw={{ easing: 'ease-out', speed: 1.2, fade: true }}>
  <svg viewBox="0 0 200 100">
    <path d="M10 50 Q 100 10 190 50" stroke="#111" fill="none" />
  </svg>
</div>

When you need the instance

Replayable.svelte
<script>
  import { createScrollDraw } from 'svg-scroll-draw/svelte';

  // createScrollDraw returns [action, getInstance]
  const [draw, getInstance] = createScrollDraw({ easing: 'ease-out' });
</script>

<div use:draw>
  <svg viewBox="0 0 200 100">
    <path d="M10 50 Q 100 10 190 50" stroke="#111" fill="none" />
  </svg>
</div>

<button on:click={() => getInstance()?.replay()}>Replay</button>

Text, counters and any CSS property

Stats.svelte
<script>
  import { scrollAnimate, scrollTextAction, scrollCounterAction }
    from 'svg-scroll-draw/svelte';
</script>

<h2 use:scrollTextAction={{ split: 'words', stagger: 0.05 }}>
  Every API, one package.
</h2>

<div use:scrollAnimate={{ from: { opacity: 0, y: 24 } }}>
  <span use:scrollCounterAction={{ to: 48000 }}>0</span>
</div>

Worth knowing: Note the naming: the draw and animate actions are scrollDraw and scrollAnimate, but text, counter and video are scrollTextAction, scrollCounterAction and scrollVideoAction — suffixed so they do not collide with the core functions of the same name if you import both.

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 →

Svelte questions.

How do I animate on scroll in Svelte?

Import the scrollDraw action from svg-scroll-draw/svelte and apply it with use:scrollDraw={{ … }} on the element wrapping your SVG. Actions add no wrapper element, and Svelte destroys the instance automatically when the node is removed.

Does it work with SvelteKit and SSR?

Yes. Svelte actions only run in the browser after the node is created, so nothing executes during server rendering. No onMount guard or browser check is needed.

How do I replay or pause a Svelte scroll animation?

Use createScrollDraw instead of the bare action. It returns a tuple of the action and a getInstance function, giving you access to replay, pause, resume, seek, getProgress and destroy on the underlying instance.