Animation

The basic syntax for motion components deviates a bit from framer-motion. The equivalent to a motion.div looks like this:

<Motion let:motion><div use:motion/></Motion>

The outer Motion-component passes an action via a slot prop to the inner div-element.

The reason to deviate is the design of Svelte. I’ve studied the differences between React and Svelte a bit and one observation is that Svelte offers quite a few syntactical goodies, which only work with DOM-elements. The list includes actions, class directives, events, transitions and some special bindings like ‘bind:group`. Thus, Component libraries should avoid taking away the DOM-elements from the user, in my opinion.

If you only want to animate a div, you can also use the MotionDiv component, which corresponds to a motion.div in framer-motion:

import {MotionDiv} from 'svelte-motion'

Basic Animation

You can easily animate components with the animate, transition and variants props of the Motion component. Application is completely equivalent to framer-motion

Here is a simple example (REPL):

<script>
    import { Motion } from 'svelte-motion';
    let i = 0;
</script>

<Motion animate={{ rotate: i }} transition={{ duration: .5 }} let:motion>
    <div use:motion/>
</Motion>
<button on:click={ () => i+=45 }>turn</button>

Here is a bigger example. It shows the use of

  1. animation & transition prop
  2. alternative easing functions in transition prop
  3. keyframes
  4. variants
/ REPL

Dynamic variants, propagation and orchestration

You can control the order of animations in several ways. In the next example, the first list (1,2,3) is controlled via dynamic variants. You can control delay and other props of the variants with the custom prop of the Motion component.
On the second list it shows how animations propagate down to child elements. The outer Motion-component on the ul-element orchestrates the animation of its children.

/ REPL
  • 1
  • 2
  • 3
  • a
  • b
  • c

Exit Animation

You can animate the unmount of a component with an AnimatePresence component. The syntax is slightly different compared to framer-motion. AnimatePresence takes a prop list, which should be an array of objects. All items in the array list render one instance of the child of the AnimatePresence. The objects should have a unique attribute key. The object can be retained via the slot prop item. Then you can use the exit prop in the child Motion. Here is an example which demonstrates it:

/ REPL
example

The current syntax is more complicated than the stock-Svelte out-transition, but for orchestration of animations it may be worth the overhead.

Animation Controls

With useAnimation you can create animation controls. These can be passed to one or more Motion components into the animate prop. With this, you can start and stop animations more easily in your code.

import { useAnimation } from 'svelte-motion'

const controls = useAnimation();

The start method of the animation control object returns a promise. This makes it easy to create sequences of animation. In the example below, many boxes are grouped in a grid. When you click on one of the small boxes, all boxes fade out delayed in a circular way, starting at the box you clicked. To make this work, the custom prop is used. The delay is distorted at random, so it is not trivial to determine, how long the animation takes. Awaiting the promise is a simple solution.

/ REPL

Animation Lifecycles

When using the animate prop to add motion to your components, you can pass a callback to these three lifecycle props:

const onUpdate = ({opacity,x}) => {//do something}
<Motion animate={"myVariant"} onComplete={(definition)=>{/*definition is "myVariant" */}}>...
<Motion animate={{x:100,opacity:0}} onComplete=={(definition)=>{/*definition is {x:100,opacity:0}*/}}/>...

This REPL demonstrate the usage of all three lifecycles.