MotionValue
MotionValues track the state and velocity of animating values.
All motion
components internally use MotionValue
s to track the state and velocity of an animating value.
Usually, these are created automatically. But for advanced use-cases, it is possible to create them manually and inject them into motion
components.
import { motion, useMotionValue } from "framer-motion"
export function MyComponent() { const x = useMotionValue(0) return <motion.div style={{ x }} />}
By manually creating MotionValue
s you can:
- Set and get their state.
- Pass to multiple components to synchronise motion across them.
- Chain
MotionValue
s via theuseTransform
hook. - Update visual properties without triggering React's render cycle.
const x = useMotionValue(0)const input = [-200, 0, 200]const output = [0, 1, 0]const opacity = useTransform(x, input, output)
return <motion.div drag="x" style={{ x, opacity }} />
#Overview
MotionValue
s can be created with the useMotionValue
hook.
The value passed to useMotionValue
will act as the initial state of the MotionValue
.
const x = useMotionValue(0)
It can be updated with the set
method. This won't trigger a React re-render.
x.set(100)
A MotionValue
can be any string or number. We can read the value with the get
method.
x.get() // 100
MotionValue
s containing a single number can return a velocity via the getVelocity
method. This returns the velocity as calculated per second to account for variations in frame rate across devices.
x.getVelocity()
If a MotionValue
contains a color, or more than one number, getVelocity
will always return 0
.
#Injecting MotionValue
s
Once a MotionValue
has been created, it can be injected into the motion
component in the same way you'd usually set that visual property.
For HTML components, that's via the style
attribute.
const x = useMotionValue(0)
return <motion.div style={{ x }} />
For SVG components, that's directly into the attribute itself.
const cx = useMotionValue(0)
return <motion.circle cx={cx} />
It is possible to inject a single MotionValue
into one or more components. Changes in the MotionValue
will be reflected in all the components.
#Responding to changes
Listeners can be added to MotionValue
s with the onChange
method. onChange
returns an unsubscribe method, so it works quite naturally with useEffect
.
useEffect(() => x.onChange(latest => {}), [])
#Creating child MotionValue
s
Any MotionValue
can spawn children MotionValue
s that update whenever their parent does. This allows the creation of value chains for declarative effects.
Using the useTransform
hook, we can pass the latest value through an update function that can take the latest parent value and transform it before returning it to update the child.
const y = useTransform(x, latest => latest * 2)
useTransform
can also accept value ranges that can map from a linear series of numbers into non-linear series of numbers, colors or a complex string.
const xInput = [-100, 0, 100]const opacityOutput = [0, 1, 0]const colorOutput = ["#f00", "#fff", "#0f0"]
const opacity = useTransform(x, xInput, opacityOutput)const color = useTransform(x, xInput, colorOutput)
These child components can be used exactly like the parents. They can be passed to the same component, a different component, or multiple other components.
#Utilities
#useMotionValue
#useMotionValue(initial): MotionValue<T>
Creates a MotionValue
to track the state and velocity of a value.
Usually, these are created automatically. For advanced use-cases, like use with useTransform
, you can create MotionValue
s externally and pass them into the animated component via the style
prop.
initial: T
The initial state
returns: MotionValue<T>
export const MyComponent = () => { const scale = useMotionValue(1)
return <motion.div style={{ scale }} />}
#useMotionTemplate
#useMotionTemplate(fragments, values): MotionValue<string>
Combine multiple motion values into a new one using a string template literal.
fragments: TemplateStringsArray
values: MotionValue[]
returns: MotionValue<string>
import { motion, useSpring, useMotionValue, useMotionTemplate} from "framer-motion"
function Component() { const shadowX = useSpring(0) const shadowY = useMotionValue(0) const shadow = useMotionTemplate`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))`
return <motion.div style={{ filter: shadow }} />}
#useTransform
#useTransform(value, inputRange, outputRange, options): MotionValue<O>
Create a MotionValue
that transforms the output of another MotionValue
by mapping it from one range of values into another.
Given an input range of [-200, -100, 100, 200]
and an output range of [0, 1, 1, 0]
, the returned MotionValue
will:
- When provided a value between
-200
and-100
, will return a value between0
and1
. - When provided a value between
-100
and100
, will return1
. When provided a value between100
and200
, will return a value between1
and0
The input range must be a linear series of numbers. The output range can be any value type supported by Framer Motion: numbers, colors, shadows, etc.
Every value in the output range must be of the same type and in the same format.
value: MotionValue<number>
inputRange: InputRange
A linear series of numbers (either all increasing or decreasing)
outputRange: O[]
A series of numbers, colors or strings. Must be the same length as inputRange
options: TransformOptions<O>
clamp: boolean
: Clamp values to within the given range. Defaults totrue
ease: EasingFunction[]
: Easing functions to use on the interpolations between each value in the input and output ranges. If provided as an array, the array must be one item shorter than the input and output ranges, as the easings apply to the transition between each.
returns: MotionValue<O>
export const MyComponent = () => { const x = useMotionValue(0) const xRange = [-200, -100, 100, 200] const opacityRange = [0, 1, 1, 0] const opacity = useTransform(x, xRange, opacityRange)
return ( <motion.div animate={{ x: 200 }} style={{ opacity, x }} /> )}
#useTransform(input, transformer): MotionValue<O>
Create a MotionValue
that transforms the output of another MotionValue
through a function. In this example, y
will always be double x
.
input: MotionValue<I>
A MotionValue
that will pass its latest value through transform
to update the returned MotionValue
transformer: SingleTransformer<I, O>
A function that accepts the latest value from input
and returns a new value
returns: MotionValue<O>
export const MyComponent = () => { const x = useMotionValue(10) const y = useTransform(x, value => value * 2)
return <motion.div style={{ x, y }} />}
#useTransform(input, transformer): MotionValue<O>
Pass an array of MotionValue
s and a function to combine them. In this example, z
will be the x
multiplied by y
.
input: MotionValue<string | number>[]
An array of MotionValue
s that will pass their latest values through transform
to update the returned MotionValue
transformer: MultiTransformer<I, O>
A function that accepts the latest values from input
and returns a new value
returns: MotionValue<O>
export const MyComponent = () => { const x = useMotionValue(0) const y = useMotionValue(0) const z = useTransform([x, y], [latestX, latestY] => latestX * latestY)
return <motion.div style={{ x, y, z }} />}
#useSpring
#useSpring(source, config): MotionValue<any>
Creates a MotionValue
that, when set
, will use a spring animation to animate to its new state.
It can either work as a stand-alone MotionValue
by initialising it with a value, or as a subscriber to another MotionValue
.
source: MotionValue | number
MotionValue
or number. If provided a MotionValue
, when the input MotionValue
changes, the created MotionValue
will spring towards that value
options: SpringOptions
Configuration options for the spring
returns: MotionValue<any>
const x = useSpring(0, { stiffness: 300 })const y = useSpring(x, { damping: 10 })
#useTime
#useTime(): MotionValue<number>
Returns a MotionValue
that updates once per animation frame with the duration, in milliseconds, since the hook was first called.
const time = useTime()const rotate = useTransform( time, [0, 1000], // milliseconds [0, 360])
#useElementScroll
#useElementScroll(ref): ScrollMotionValues
Returns MotionValues that update when the provided element scrolls:
scrollX
— Horizontal scroll distance in pixels.scrollY
— Vertical scroll distance in pixels.scrollXProgress
— Horizontal scroll progress between0
and1
.scrollYProgress
— Vertical scroll progress between0
and1
.
This element must be set to overflow: scroll
on either or both axes to report scroll offset.
ref: RefObject<HTMLElement>
returns: ScrollMotionValues
export const MyComponent = () => { const ref = useRef() const { scrollYProgress } = useElementScroll(ref)
return ( <div ref={ref}> <motion.div style={{ scaleX: scrollYProgress }} /> </div> )}
#useViewportScroll
#useViewportScroll(): ScrollMotionValues
Returns MotionValues that update when the viewport scrolls:
scrollX
— Horizontal scroll distance in pixels.scrollY
— Vertical scroll distance in pixels.scrollXProgress
— Horizontal scroll progress between0
and1
.scrollYProgress
— Vertical scroll progress between0
and1
.
Warning: Setting body
or html
to height: 100%
or similar will break the Progress
values as this breaks the browser's capability to accurately measure the page length.
export const MyComponent = () => { const { scrollYProgress } = useViewportScroll() return <motion.div style={{ scaleX: scrollYProgress }} />}
#useVelocity
#useVelocity(value): MotionValue<number>
Creates a MotionValue
that updates when the velocity of the provided MotionValue
changes.
value: MotionValue<number>
returns: MotionValue<number>
const x = useMotionValue(0)const xVelocity = useVelocity(x)const xAcceleration = useVelocity(xVelocity)
#MotionValue
A MotionValue
has the following methods, with which you can query use to affect its state.
#get(): V
Returns the latest state of MotionValue
.
returns: V
The latest state of MotionValue
#getVelocity(): number
Returns the latest velocity of MotionValue
.
returns: number
The latest velocity of MotionValue
. Returns 0
if the state is nonnumerical
#set(v, render): void
Sets the state of the MotionValue
.
v: V
Latest value to set
render: boolean
Whether to notify render subscribers. Defaults to true
const x = useMotionValue(0)x.set(10)
#isAnimating(): boolean
Returns true
if this value is currently animating.
returns: boolean
#stop(): void
Stop the currently active animation.
#onChange(subscription): () => void
When calling onChange
inside a React component, it should be wrapped with the useEffect
hook. As it returns an unsubscribe function, this should be returned from the useEffect
function to ensure you don't add duplicate subscribers.
subscription: Subscriber<V>
A function that receives the latest value
returns: () => void
A function that, when called, will cancel this subscription
export const MyComponent = () => { const x = useMotionValue(0) const y = useMotionValue(0) const opacity = useMotionValue(1)
useEffect(() => { function updateOpacity() { const maxXY = Math.max(x.get(), y.get()) const newOpacity = transform(maxXY, [0, 100], [1, 0]) opacity.set(newOpacity) }
const unsubscribeX = x.onChange(updateOpacity) const unsubscribeY = y.onChange(updateOpacity)
return () => { unsubscribeX() unsubscribeY() } }, [])
return <motion.div style={{ x }} />}
#destroy(): void
Destroy and clean up subscribers to this MotionValue
.
The MotionValue
hooks like useMotionValue
and useTransform
automatically handle the lifecycle of the returned MotionValue
, so this method is only necessary if you've manually created a MotionValue
via the motionValue
function.