motion-solid

Motion values

A motion value holds one animatable value, like an x offset or a color, and tracks its velocity. motion components write motion values to the DOM on every frame without going through Solid, so a value that changes 60 times a second doesn't run any Solid computation.

Usage

useMotionValue(initial) creates a motion value. Pass it to a motion component in style:

import { motion, useMotionValue } from "@motion-s/solid"

const x = useMotionValue(0)

<motion.div style={{ x }} />

When x changes, the element moves. No signal is written and no effect runs.

motion components already create a motion value for every value they animate. Create your own when you want to share a value between elements, derive other values from it with useTransform, or read and set it yourself.

useMotionValue returns motion-dom's motionValue(initial), which is also exported and can be used outside components.

Reading and setting

MethodWhat it does
get()Returns the current value.
set(value)Sets the value. Elements that use it are updated in the next frame.
jump(value)Sets the value, stops the running animation and resets the velocity to 0.
getPrevious()Returns the value before the last change.
getVelocity()Returns the velocity in units per second, 0 for values that aren't numbers.
isAnimating()Whether an animation is running on the value.
stop()Stops the running animation.
on(event, callback)Subscribes to an event and returns a function that unsubscribes.

The events are:

EventFires
changeWhen the value changes, with the new value.
animationStartWhen an animation starts on the value.
animationCompleteWhen an animation finishes.
animationCancelWhen an animation is stopped before it finishes.
destroyWhen the value is destroyed.

In a component, subscribe with useMotionValueEvent: it unsubscribes when the component is disposed.

Styles, attributes and text

A motion value can go in style for any value Motion can animate: transforms like x, scale or rotate, and CSS properties like opacity or backgroundColor.

On SVG elements, motion values can also be passed as attributes:

const cx = useMotionValue(50)

<motion.circle cx={cx} cy={50} r={10} />

A motion value passed as the only child of a motion component is rendered as its text content. Here, rounded is derived from x with useTransform and shown next to the box you drag:

x: 0

Animating a motion value

animate() animates a motion value directly. Starting a new animation on a value stops the one that's running:

import { animate, useMotionValue } from "@motion-s/solid"

const x = useMotionValue(0)

animate(x, 100, { type: "spring", bounce: 0.3 })

jump and stop end a running animation. set doesn't: the animation keeps writing to the value on the next frame.

Motion values and Solid

Motion values aren't Solid signals. Calling x.get() in JSX, a memo or an effect doesn't track x: they won't run again when x changes. This is on purpose. Motion updates values on every frame and tracks their velocity; if every update went through Solid, every computation reading a motion value would run every frame.

Instead, the two meet where you ask them to:

DirectionUse
Solid → motion valueuseTransform(() => …), useSpring(accessor), accessor arguments
Motion value → DOMPass it to a motion component. Solid isn't involved.
Motion value → SoliduseMotionValueState(value) returns an accessor
Motion value → side effectsuseMotionValueEvent(value, "change", callback)
const [target, setTarget] = createSignal(0)
const [selected, setSelected] = createSignal(false)

// Solid → motion value
const x = useSpring(target)
const scale = useTransform(() => (selected() ? 1.2 : 1))

// Motion value → DOM
<motion.div style={{ x, scale }} />

// Motion value → Solid
const latest = useMotionValueState(x)
<Show when={latest() > 100}>Far enough</Show>

// Motion value → side effects
useMotionValueEvent(x, "animationComplete", () => console.log("done"))

From Solid to a motion value

useTransform with a single function creates a motion value from Solid signals, other motion values, or both. It runs again when any of them changes. useSpring with an accessor animates towards the accessor's value whenever it changes.

Hook arguments that can change are accessors, as elsewhere in Solid. For example, a range that depends on a signal: useTransform(x, () => [0, max()], [0, 1]). Options objects can be an accessor or an object with getters.

From a motion value to Solid

useMotionValueState(value) returns a read-only accessor of a motion value. Use it for logic and text: <Show>, memos, labels. It's updated through Solid's scheduler, so it follows Solid's batching and transitions like any signal. See useMotionValueState.

In this demo, the range input sets a signal, a spring follows it, and an accessor of the spring decides the text:

Before the line

Side effects

To run code when a motion value changes or an animation starts or ends, use useMotionValueEvent. It doesn't involve Solid's scheduler: the callback runs when Motion notifies.

API reference

function useMotionValue<T>(initial: T): MotionValue<T>
  • initial: the starting value, such as a number, a string with a unit ("10px") or a color.

Returns a MotionValue<T>, the same object as motionValue(initial) from motion-dom.