logo svelte /motion v0.9.3
FIG-001 · BLOG POST
// notes / migrating-from-svelte-motion

migrating from svelte-motion to svelte motion.

Move from the dormant svelte-motion package to @humanspeak/svelte-motion for Svelte 5 runes, AnimatePresence, gestures, drag, layout animations, and SSR-safe SvelteKit support.

FIG-001
SHEET 01 / 02

The unscoped svelte-motion package has not released since February 2024. It still has users, name recognition, and a familiar component model, but it predates Svelte 5’s runes-first ecosystem.

@humanspeak/svelte-motion is an actively maintained alternative built specifically for Svelte 5. It tracks the modern Motion API and includes AnimatePresence, gestures, drag, FLIP layout animation, shared-layout transitions, springs, scroll-linked values, and SSR-safe SvelteKit rendering.

This is a source migration rather than a package alias. The concepts transfer cleanly, but imports and component names need to change.

Replace the package

Remove the old dependency and install the scoped package:

pnpm remove svelte-motion
pnpm add @humanspeak/svelte-motion
pnpm remove svelte-motion
pnpm add @humanspeak/svelte-motion

Then replace generic Motion imports with either the familiar proxy API or tree-shakeable named components:

<script lang="ts">
    import { motion } from '@humanspeak/svelte-motion'
</script>

<motion.div
    initial={{ opacity: 0, y: 12 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{ type: 'spring', stiffness: 320, damping: 24 }}
>
    Migrated
</motion.div>
<script lang="ts">
    import { motion } from '@humanspeak/svelte-motion'
</script>

<motion.div
    initial={{ opacity: 0, y: 12 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{ type: 'spring', stiffness: 320, damping: 24 }}
>
    Migrated
</motion.div>

Use motion.div, motion.button, and the other element proxies when API familiarity matters most. Use MotionDiv, MotionButton, and the named exports when you want the smallest tree-shaken surface.

Map the animation concepts

Most animation intent transfers directly:

svelte-motion concept@humanspeak/svelte-motion equivalent
Motionmotion.div or MotionDiv
initial, animate, transitionThe same prop names and semantics
exitexit inside AnimatePresence
VariantsVariants with parent-to-child propagation
DragDrag with constraints, momentum, elastic, and axis locking
Layout animationlayout and shared layoutId transitions

The API reference lists the complete modern Framer Motion-style surface.

Migrate conditional exit animations

Elements cannot animate after Svelte removes them unless something owns their presence lifecycle. Wrap conditional content in AnimatePresence:

<script lang="ts">
    import { AnimatePresence, motion } from '@humanspeak/svelte-motion'
    let open = $state(true)
</script>

<AnimatePresence>
    {#if open}
        <motion.div
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
        >Content</motion.div>
    {/if}
</AnimatePresence>
<script lang="ts">
    import { AnimatePresence, motion } from '@humanspeak/svelte-motion'
    let open = $state(true)
</script>

<AnimatePresence>
    {#if open}
        <motion.div
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
        >Content</motion.div>
    {/if}
</AnimatePresence>

Use mode="wait" for sequential replacement and mode="popLayout" when exiting items should immediately leave document flow. The live AnimatePresence example shows the modes in action.

Replace manual gesture state

Move transient hover, press, focus, and viewport animation into whileHover, whileTap, whileFocus, and whileInView. Try the hover and tap example and focus example.

Use layout animation instead of measuring boxes

Add layout when an element should animate between its old and new position or size. Use a matching layoutId across UI states to create a shared-element transition. See reordering and shared layout animation.

Move state to Svelte 5 runes

Keep application state in $state, compute targets with $derived, and use Motion values for continuously updating animation data:

  • useMotionValue stores an animatable value without forcing component rerenders.
  • useSpring follows another value with spring physics.
  • useTransform maps an input range into another value.
  • useScroll supplies page or element scroll progress.

The motion values guide explains when to use runes and when a Motion value is the better tool.

Verify the migration

Before removing the old package from your lockfile:

  1. Search for every import from svelte-motion.
  2. Verify conditional elements finish their exit animations.
  3. Test drag constraints and layout transitions at responsive breakpoints.
  4. Load animated routes directly in SvelteKit to exercise SSR and hydration.
  5. Test keyboard focus and the operating system’s reduced-motion preference.
  6. Check variants that rely on parent-to-child propagation.

The package requires Svelte 5 and does not provide a Svelte 4 compatibility layer. That sharper baseline enables its runes-native API, SSR behavior, and current Motion parity.

Start with the getting-started guide, then browse the live examples for the patterns used by your application.

← all posts
migrating-from-svelte-motion August 23, 2026 7 min
↩ to top