An open API service indexing awesome lists of open source software.

https://github.com/humanspeak/svelte-motion

Framer Motion for Svelte 5. Declarative motion.<tag> components with AnimatePresence exit animations, gestures (hover, tap, drag, focus, in-view), variants, FLIP layout animations, shared-layout transitions, spring physics, and scroll-linked motion values. The drop-in Framer Motion alternative for Svelte and SvelteKit.
https://github.com/humanspeak/svelte-motion

animate-presence animation animation-library drag framer-motion framer-motion-alternative framer-motion-svelte gestures layout-animations motion scroll-animation spring-animation ssr svelte svelte-5 svelte-animation svelte-motion sveltekit typescript variants

Last synced: 9 days ago
JSON representation

Framer Motion for Svelte 5. Declarative motion.<tag> components with AnimatePresence exit animations, gestures (hover, tap, drag, focus, in-view), variants, FLIP layout animations, shared-layout transitions, spring physics, and scroll-linked motion values. The drop-in Framer Motion alternative for Svelte and SvelteKit.

Awesome Lists containing this project

README

          

# Svelte Motion — Framer Motion API for Svelte 5

[![NPM version](https://img.shields.io/npm/v/@humanspeak/svelte-motion.svg)](https://www.npmjs.com/package/@humanspeak/svelte-motion)
[![AI tokens used building this repo — TokenMaxing](https://tokenmaxing.app/badge/humanspeak/svelte-motion)](https://tokenmaxing.app/card/humanspeak/svelte-motion)
[![Build Status](https://github.com/humanspeak/svelte-motion/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/humanspeak/svelte-motion/actions/workflows/npm-publish.yml)
[![Coverage Status](https://coveralls.io/repos/github/humanspeak/svelte-motion/badge.svg?branch=main)](https://coveralls.io/github/humanspeak/svelte-motion?branch=main)
[![License](https://img.shields.io/npm/l/@humanspeak/svelte-motion.svg)](https://github.com/humanspeak/svelte-motion/blob/main/LICENSE)
[![Downloads](https://img.shields.io/npm/dm/@humanspeak/svelte-motion.svg)](https://www.npmjs.com/package/@humanspeak/svelte-motion)
[![CodeQL](https://github.com/humanspeak/svelte-motion/actions/workflows/codeql.yml/badge.svg)](https://github.com/humanspeak/svelte-motion/actions/workflows/codeql.yml)
[![Install size](https://packagephobia.com/badge?p=@humanspeak/svelte-motion)](https://packagephobia.com/result?p=@humanspeak/svelte-motion)
[![Code Style: Trunk](https://img.shields.io/badge/code%20style-trunk-blue.svg)](https://trunk.io)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
[![Types](https://img.shields.io/npm/types/@humanspeak/svelte-motion.svg)](https://www.npmjs.com/package/@humanspeak/svelte-motion)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/humanspeak/svelte-motion/graphs/commit-activity)

Svelte Motion brings a Framer Motion-style API to Svelte 5 with `motion.` components, gestures, variants, exit animations, layout animation, and utility hooks.

For the latest documentation and examples, visit [motion.svelte.page](https://motion.svelte.page).

## Install

```bash
npm install @humanspeak/svelte-motion
```

```svelte

import { motion } from '@humanspeak/svelte-motion'

Hello motion

```

## Framer Motion API Parity

Goal: Framer Motion API parity for Svelte where common React examples can be translated with minimal changes.

| Capability | Status |
| ---------------------------------------------------------------------- | ------------------------------------------ |
| `initial` / `animate` / `transition` | Supported |
| `variants` (string keys + inheritance, function-form `custom`) | Supported |
| `whileHover` / `whileTap` / `whileFocus` / `whileDrag` / `whileInView` | Supported (inline + variant keys / arrays) |
| Drag (`drag`, constraints, momentum, controls, callbacks) | Supported |
| `AnimatePresence` (`initial`, `mode`, `onExitComplete`) | Supported |
| Layout (`layout`, `layout="position"`) | Supported (single-element FLIP) |
| Shared layout (`layoutId`, `LayoutGroup`, `layoutScroll`) | Supported |
| Reorder (`Reorder.Group`, `Reorder.Item`, edge auto-scroll) | Supported |
| View Transitions (`animateView`, shared-element morphs) | Supported |
| Vanilla values (`motionValue`, `styleEffect`, `toMotionValue` bridge) | Supported |
| Pan gesture API (`onPan*`, `onPanSessionStart`) | Supported |
| `MotionConfig` parity beyond `transition` | Partial |
| `reducedMotion`, `features`, `transformPagePoint` | Not yet supported |

## Supported elements

Motion components are generated from canonical HTML/SVG tag lists and exported from `src/lib/html/`.

- `motion.div`, `motion.button`, `motion.svg`, `motion.path`, etc.
- Most standard tags are included.
- Excluded by generation: `script`, `style`, `link`, `meta`, `title`, `head`, `html`, `body`.

## Core components

### `motion.`

Use motion components the same way you use regular elements, with animation props:

```svelte

```

### `MotionConfig`

`MotionConfig` currently supports default `transition` values for descendants.

```svelte

import { MotionConfig, motion } from '@humanspeak/svelte-motion'

```

### `AnimatePresence`

Exit animations on unmount with support for `mode="sync" | "wait" | "popLayout"` and `onExitComplete`.

```svelte

import { AnimatePresence, motion } from '@humanspeak/svelte-motion'

let show = $state(true)

console.log('done')}>
{#if show}

{/if}

(show = !show)}>Toggle
```

Notes:

- Direct children of `AnimatePresence` require `key`.
- Exit transition precedence: base `{ duration: 0.35 }` < merged `transition` < `exit.transition`.

## Interaction props

### `whileHover`

```svelte

```

- Uses true-hover gating (`(hover: hover)` and `(pointer: fine)`).
- Supports `onHoverStart` and `onHoverEnd`.

### `whileTap`

```svelte

```

- Supports `onTapStart`, `onTap`, `onTapCancel`.
- Keyboard accessible (Enter/Space).

### `whileFocus`

```svelte

```

- Supports `onFocusStart` and `onFocusEnd`.

### `whileInView`

```svelte
console.log('entered')}
onInViewEnd={() => console.log('left')}
/>
```

- Uses `IntersectionObserver`.
- Current implementation uses a fixed threshold behavior (no Framer-style `viewport` options yet).

## Drag

Supported drag props:

- `drag`: `true | 'x' | 'y'`
- `dragConstraints`: pixel object or element ref
- `dragElastic`, `dragMomentum`, `dragTransition`
- `dragDirectionLock`, `dragPropagation`, `dragSnapToOrigin`
- `dragListener`, `dragControls`
- `whileDrag`
- Callbacks: `onDragStart`, `onDrag`, `onDragEnd`, `onDirectionLock`, `onDragTransitionEnd`

```svelte

import { createDragControls, motion } from '@humanspeak/svelte-motion'

const controls = createDragControls()

controls.start(e)}>Start drag

```

## Variants

```svelte

import { motion, type Variants } from '@humanspeak/svelte-motion'

let open = $state(false)

const parent: Variants = {
open: { opacity: 1 },
closed: { opacity: 0 }
}

const child: Variants = {
open: { x: 0, opacity: 1 },
closed: { x: -16, opacity: 0 }
}

Item A
Item B

```

- String variant keys are resolved from `variants`.
- Variant state inherits through context.
- A variant entry can be a `(custom) => keyframes` factory. The `custom` prop is forwarded — useful for staggered lists where each child needs its own offset or delay. Children without `custom` inherit the nearest motion ancestor's value.

```svelte

import { motion, type Variants } from '@humanspeak/svelte-motion'

const variants: Variants = {
hidden: { opacity: 0, x: -100 },
visible: (i) => ({
opacity: 1,
x: 0,
transition: { delay: (i as number) * 0.1 }
})
}
const items = ['Alpha', 'Beta', 'Gamma', 'Delta']

{#each items as item, i}

{item}

{/each}
```

## Layout animation

Single-element FLIP layout animation:

```svelte

```

- `layout`: translate + scale.
- `layout="position"`: translate only.
- Shared layout (`layoutId`) is not implemented yet.

## Utilities

- `useAnimationFrame`
- `useMotionTemplate`
- `useSpring`
- `useTime`
- `useTransform`
- `useVelocity`
- `styleString`
- `stringifyStyleObject` (deprecated)
- `createDragControls`

The package also re-exports core helpers from `motion` (for example `animate`, `stagger`, `transform`, easings, and utility functions).

## SSR behavior

- Initial visual state is rendered server-side from `initial` (or first `animate` keyframe when `initial` is empty).
- `initial={false}` skips initial enter animation.
- Hydration path is designed to avoid flicker.

## Verification snapshot

Validated against current source and test suite (local run):

- Unit/component tests: `676 passed`
- E2E tests: `290 passed`, `2 skipped`

## Known gaps vs Framer Motion

- `whileInView` does not yet expose Framer-style viewport options.
- `MotionConfig` currently only provides `transition` defaults.
- `reducedMotion`, `features`, and `transformPagePoint` are not implemented as `MotionConfig` props.

## External dependencies

- `motion`
- `motion-dom`

## Svelte 5 ecosystem

Part of the [Humanspeak](https://humanspeak.com) family of runes-native Svelte 5 packages:

| Package | Description |
| --- | --- |
| [@humanspeak/svelte-markdown](https://markdown.svelte.page) | Runtime markdown renderer for Svelte |
| [@humanspeak/svelte-virtual-list](https://virtuallist.svelte.page) | Virtual scrolling for Svelte |
| **[@humanspeak/svelte-motion](https://motion.svelte.page)** — _this package_ | Framer Motion for Svelte 5 |
| [@humanspeak/svelte-headless-table](https://table.svelte.page) | Headless data tables for Svelte |
| [@humanspeak/svelte-diff](https://diff.svelte.page) | Diff comparison for Svelte |
| [@humanspeak/svelte-purify](https://purify.svelte.page) | HTML sanitisation for Svelte |
| [@humanspeak/svelte-virtual-chat](https://virtualchat.svelte.page) | Virtual chat viewport for Svelte 5 |
| [@humanspeak/memory-cache](https://memory.svelte.page) | In-memory cache for TypeScript |
| [@humanspeak/svelte-json-view-lite](https://jsonview.svelte.page) | JSON tree viewer for Svelte 5 |
| [@humanspeak/svelte-scoped-props](https://scoped.svelte.page) | Scoped class props for Svelte |

## License

MIT © [Humanspeak, Inc.](LICENSE)

## Credits

Made with ❤️ by [Humanspeak](https://humanspeak.com)