Get started with Svelte Motion
Svelte Motion is a Svelte animation library for building smooth, production-grade UI animations. You can start with simple prop-based animations before growing to layout, gesture and scroll animations.
Svelte Motion’s unique hybrid engine combines the performance of native browser animations with the flexibility of JavaScript. It’s designed to feel like a natural extension of Svelte’s reactive philosophy.
In this guide, we’ll learn why and when you should use Svelte Motion, how to install it, and then take a whirlwind tour of its main features.
Why Svelte Motion?
Svelte gives you the power to build dynamic user interfaces with excellent performance out of the box. Svelte Motion extends this power to animations, making it simple to create everything from beautiful micro-interactions to complex, gesture-driven animations.
<script lang="ts">
import { motion } from '@humanspeak/svelte-motion'
</script>
<motion.button
class="my-4 rounded-md border border-border bg-blue-300 px-4 py-2 text-text-primary"
animate={{ opacity: 1 }}
initial={{ opacity: 0 }}
transition={{ duration: 0.6 }}
>
Animated button
</motion.button>
Key advantages
Here’s when it’s the right choice for your project.
- Built for Svelte. Sometimes finding examples for animations with Svelte can be tricky. Svelte Motion is attempting to provide an exact copy of the Motion for React API which there is a lot of examples for out there in the wild.
- Animate anything. CSS has hard limits. There are values you can’t animate, keyframes you can’t interrupt, staggers that must be hardcoded. Svelte Motion provides a single, consistent API that handles everything from simple transitions to advanced scroll, layout, and gesture-driven effects.
- App-like gestures. Standard CSS
:hover
events can be unreliable on touch devices. Svelte Motion provides robust, cross-device gesture recognizers for tap and hover.
When is CSS a better choice?
For simple, self-contained effects (like a color change on hover) a standard CSS transition is a lightweight solution. The strength of Svelte Motion is that it can do these simple kinds of animations but also scale to anything you can imagine—using the same easy to write and maintain API.
Install
Svelte Motion is available via npm:
npm install @humanspeak/svelte-motion
Features can now be imported:
import { motion } from '@humanspeak/svelte-motion'
Your first animation
The <motion>
component is the core API in Svelte Motion. It’s a DOM element, supercharged with animation capabilities.
<script>
import { motion } from '@humanspeak/svelte-motion';
</script>
<motion.ul
class="size-24 rounded-md bg-pink-400"
animate={{ rotate: 360 }}
transition={{ duration: 1 }}
/>
When values in animate
change, the component will animate. Svelte Motion has intuitive defaults, but animations can of course be configured via the transition
prop.
<motion.div
animate={{
scale: 2,
transition: { duration: 2 }
}}
>
Scaling div
</motion.div>
Enter animation
When a component enters the page, it will automatically animate to the values defined in the animate
prop.
You can provide values to animate from via the initial
prop (otherwise these will be read from the DOM).
<motion.button initial={{ scale: 0 }} animate={{ scale: 1 }}>
Scaling button
</motion.button>
Or disable this initial animation entirely by setting initial
to false
.
<motion.button initial={false} animate={{ scale: 1 }}>
No initial animation
</motion.button>
Hover & tap animation
<motion>
extends Svelte’s event system with powerful gesture animations. It currently supports hover and tap.
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
Interactive button
</motion.button>
Scroll animation
Svelte Motion supports both styles of scroll animations: scroll-triggered and scroll-linked.
To trigger an animation on scroll, you can bind a class, style, or state change based on an IntersectionObserver
, or pair Motion with stores to flip between initial
and animate
states.
To link a value directly to scroll position, use utilities like useTime
/useTransform
to drive an animated style.
<script>
import { motion, useTime, useTransform } from '@humanspeak/svelte-motion'
const time = useTime()
const progress = useTransform(() => ($time % 4000) / 4000, [time])
</script>
<motion.div style={`transform: scaleX(${$progress})`}/>
Layout animation
Animate between changes in layout using transforms. It’s as easy as applying the layout
prop.
<motion.div layout />
layout
animates translation and scale between layout changes.layout="position"
animates translation only.
Exit animations
By wrapping motion components with AnimatePresence
you gain access to exit animations. This allows you to animate elements as they’re removed from the DOM. (Reference)
<script>
import { motion, AnimatePresence } from '@humanspeak/svelte-motion'
let show = $state(true)
</script>
<AnimatePresence>
{#if show}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9, transition: { duration: 0.6 } }}
transition={{ duration: 0.4 }}
class="size-24 rounded-md bg-cyan-400"
/>
{/if}
</AnimatePresence>
<motion.button whileTap={{ scale: 0.97 }} on:click={() => (show = !show)}>
Toggle
</motion.button>
Transition precedence for exit timing (merged):
exit.transition
(highest precedence)- component
transition
(merged with anyMotionConfig
defaults) - fallback
{ duration: 0.35 }
Learn next
That’s a quick overview of Svelte Motion’s basic features. Next, explore animation patterns, layout, and gestures—or dive straight into our examples. For React-oriented reference material, see the Motion for React docs (motion.dev).