Documentation

Documentation

React

motion

motion

The motion component drives most animations in Motion for React.

There's a motion component for every HTML and SVG element, for instance motion.div, motion.circle etc. Think of it as a normal React component, supercharged for 120fps animation and gestures.

Usage

Import motion from Motion:

// React
import { motion } from "motion/react"

// React Server Components
import * as motion from "motion/client"

Now you can use it exactly as you would any normal HTML/SVG component:

<motion.div className="box" />

But you also gain access to powerful animation APIs like the animate, layout, whileInView props and much more.

<motion.div
  className="box"
  // Animate when this value changes:
  animate={{ scale: 2 }}
  // Fade in when the element enters the viewport:
  whileInView={{ opacity: 1 }}
  // Animate the component when its layout changes:
  layout
  // Style now supports indepedent transforms:
  style={{ x: 100 }}
/>

Checkout the Animation guide for a full overview on animations in Motion for React.

Performance

motion components animate values outside the React render cycle for improved performance.

Using motion values instead of React state to update style will also avoid re-renders.

const x = useMotionValue(0)

useEffect(() => {
  // Won't trigger a re-render!
  const timeout = setTimeout(() => x.set(100), 1000)

  return () => clearTimeout(timeout)
}, [])

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

Server-side rendering

motion components are fully compatible with server-side rendering, meaning the initial state of the component will be reflected in the server-generated output.

// Server will output `translateX(100px)`
<motion.div initial={false} animate={{ x: 100 }} />

This is with the exception of some SVG attributes like transform which require DOM measurements to calculate.

Custom components

Any React component can be supercharged into a motion component by passing it to motion.create() as a function.

const MotionComponent = motion.create(Component)

React 18 users must use forwardRef to wrap their components and pass ref to the element they want to animate:

const Component = React.forwardRef((props, ref) => {
  return <div ref={ref} />
})

React 19 users can pass a normal component, and ref will be passed in via props:

const Component = (props) => {
  return <div ref={props.ref} />
})

Important: Make sure not to call motion.create() within another React render function! This will make a new component every render, breaking your animations.

It's also possible to pass strings to motion.create, which will create custom DOM elements.

// Will render <custom-element /> into HTML
const MotionComponent = motion.create('custom-element')

By default, all motion props (like animate etc) are filtered out of the props forwarded to the provided component. By providing a forwardMotionProps config, the provided component will receive these props.

motion.create(Component, { forwardMotionProps: true })

Props

motion components accept the following props.

Animation

initial

The initial visual state of the motion component.

This can be set as an animation target:

<motion.section initial={{ opacity: 0, x: 0 }} />

Variants:

<motion.li initial="visible" />
<motion.div initial={["visible", "active"]} />

Or set as false to disable the enter animation and initially render as the values found in animate.

<motion.div initial={false} animate={{ opacity: 0 }} />

animate

A target to animate to on enter, and on update.

Can be set as an animation target:

<motion.div
  initial={{ boxShadow: "0px 0px #000" }}
  animate={{ boxShadow: "10px 10px #000" }}
/>

Or variants:

<motion.li animate="visible" />
<motion.div initial="hidden" animate={["visible", "active"]} />

exit

A target to animate to when a component is removed from the tree. Can be set either as an animation target, or variant.

Note: Owing to React limitations, the component being removed must be a direct child of AnimatePresence to enable this animation.

<AnimatePresence>
  {isVisible && (
    <ul key="list">
      <motion.li exit={{ opacity: 0 }} />
    </ul>
  )}
</AnimatePresence>

transition

The default transition for this component to use when an animation prop (animate, whileHover etc) has no transition defined.

<motion.div transition={{ type: "spring" }} animate={{ scale: 1.2 }} />

variants

The variants for this component.

const variants = {
  active: {
      backgroundColor: "#f00"
  },
  inactive: {
    backgroundColor: "#fff",
    transition: { duration: 2 }
  }
}

return (
  <motion.div
    variants={variants}
    animate={isActive ? "active" : "inactive"}
  />
)

style

The normal React DOM style prop, with added support for motion values and independent transforms.

const x = useMotionValue(30)

return <motion.div style={{ x, rotate: 90, originX: 0.5 }} />

onUpdate

Callback triggered every frame any value on the motion component updates. It's provided a single argument with the latest values.

<motion.article
  animate={{ opacity: 1 }}
  onUpdate={latest => console.log(latest.opacity)}
/>

onAnimationStart

Callback triggered when any animation (except layout animations, see onLayoutAnimationStart) starts.

It's provided a single argument, with the target or variant name of the started animation.

<motion.circle
  animate={{ r: 10 }}
  onAnimationStart={latest => console.log(latest.r)}
/>

onAnimationComplete

Callback triggered when any animation (except layout animations, see onLayoutAnimationComplete) completes.

It's provided a single argument, with the target or variant name of the completed animation.

<motion.circle
  animate={{ r: 10 }}
  onAnimationComplete={latest => console.log(latest.r)}
/>

Hover

whileHover

Target or variants to label to while the hover gesture is active.

// As target
<motion.button whileHover={{ scale: 1.2 }} />
// As variants
<motion.div whileHover="hovered" />

onHoverStart

Callback function that fires when a pointer starts hovering over the component. Provided the triggering PointerEvent.

<motion.div onHoverStart={(event) => console.log(event)} />

onHoverEnd

Callback function that fires when a pointer stops hovering over the component. Provided the triggering PointerEvent.

<motion.div onHoverEnd={(event) => console.log(event)} />

Tap

whileTap

Target or variants to label to while the tap gesture is active.

// As target
<motion.button whileTap={{ scale: 0.9 }} />
// As variants
<motion.div whileTap="tapped" />

onTapStart

Callback function that fires when a pointer starts pressing the component. Provided the triggering PointerEvent.

<motion.div onTapStart={(event) => console.log(event)} />

onTap

Callback function that fires when a pointer stops pressing the component and the pointer was released inside the component. Provided the triggering PointerEvent.

<motion.div onTap={(event) => console.log(event)} />

onTapCancel

Callback function that fires when a pointer stops pressing the component and the pointer was released outside the component. Provided the triggering PointerEvent.

<motion.div onTapCancel={(event) => console.log(event)} />

Focus

whileFocus

Target or variants to label to while the focus gesture is active.

// As target
<motion.button whileFocus={{ outline: "dashed #000" }} />
// As variants
<motion.div whileFocus="focused" />

Pan

onPan

Callback function that fires when the pan gesture is recognised on this element.

Note: For pan gestures to work correctly with touch input, the element needs touch scrolling to be disabled on either x/y or both axis with the touch-action CSS rule.

function onPan(event, info) {
  console.log(info.point.x, info.point.y)
}

<motion.div onPan={onPan} />

Pan and drag events are provided the origin PointerEvent as well as an object info that contains x and y point values for the following:

  • point: Relative to the device or page.

  • delta: Distance since the last event.

  • offset: Distance from the original event.

  • velocity: Current velocity of the pointer.

onPanStart

Callback function that fires when a pan gesture starts. Provided the triggering PointerEvent and info.

<motion.div onPanStart={(event, info) => console.log(info.delta.x)} />

onPanEnd

Callback function that fires when a pan gesture ends. Provided the triggering PointerEvent and info.

<motion.div onPanEnd={(event, info) => console.log(info.delta.x)} />

Drag

drag

Default: false

Enable dragging for this element. Set true to drag in both directions. Set "x" or "y" to only drag in a specific direction.

<motion.div drag />

whileDrag

Target or variants to label to while the drag gesture is active.

// As target
<motion.div drag whileDrag={{ scale: 0.9 }} />
// As variants
<motion.div drag whileDrag="dragging" />

dragConstraints

Applies constraints on the draggable area.

Set as an object of optional top, left, right, and bottom values, measured in pixels:

<motion.div
  drag="x"
  dragConstraints={{ left: 0, right: 300 }}
/>

Or as a ref to another element to use its bounding box as the draggable constraints:

const MyComponent = () => {
  const constraintsRef = useRef(null)

  return (
     <motion.div ref={constraintsRef}>
         <motion.div drag dragConstraints={constraintsRef} />
     </motion.div>
  )
}

dragSnapToOrigin

Default: false

If true, the draggable element will animate back to its center/origin when released.

<motion.div drag dragSnapToOrigin />

dragElastic

Default: 0.5

The degree of movement allowed outside constraints. 0 = no movement, 1 = full movement.

Set to 0.5 by default. Can also be set as false to disable movement.

By passing an object of top/right/bottom/left, individual values can be set per constraint. Any missing values will be set to 0.

<motion.div
  drag
  dragConstraints={{ left: 0, right: 300 }}
  dragElastic={0.2}
/>

dragMomentum

Default: true

Apply momentum from the pan gesture to the component when dragging finishes. Set to true by default.

<motion.div
  drag
  dragConstraints={{ left: 0, right: 300 }}
  dragMomentum={false}
/>

dragTransition

Allows you to change dragging momentum transition. When releasing a draggable element, an animation with type "inertia" starts. The animation is based on your dragging velocity. This property allows you to customize it.

<motion.div
  drag
  dragTransition={{ bounceStiffness: 600, bounceDamping: 10 }}
/>

dragDirectionLock

Default: false

Locks drag direction into the soonest detected direction. For example, if the component is moved more on the x axis than y axis before the drag gesture kicks in, it will only drag on the x axis for the remainder of the gesture.

<motion.div drag dragDirectionLock />

dragPropagation

Default: false

Allows drag gesture propagation to child components.

<motion.div drag="x" dragPropagation />

dragControls

Usually, dragging is initiated by pressing down on a component and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we might want to initiate dragging from a different component than the draggable one.

By creating a dragControls using the useDragControls hook, we can pass this into the draggable component's dragControls prop. It exposes a start method that can start dragging from pointer events on other components.

const dragControls = useDragControls()

function startDrag(event) {
  dragControls.start(event, { snapToCursor: true })
}

return (
  <>
    <div onPointerDown={startDrag} />
    <motion.div drag="x" dragControls={dragControls} />
  </>
)

Note: Given that by setting dragControls you are taking control of initiating the drag gesture, it is possible to disable the draggable element as the initiator by setting dragListener={false}.

dragListener

Determines whether to trigger the drag gesture from event listeners. If passing dragControls, setting this to false will ensure dragging can only be initiated by the controls, rather than a pointerdown event on the draggable element.

onDrag

Callback function that fires when the drag gesture is recognised on this element.

function onDrag(event, info) {
  console.log(info.point.x, info.point.y)
}

<motion.div drag onDrag={onDrag} />

Pan and drag events are provided the origin PointerEvent as well as an object info that contains x and y point values for the following:

  • point: Relative to the device or page.

  • delta: Distance since the last event.

  • offset: Distance from the original event.

  • velocity: Current velocity of the pointer.

onDragStart

Callback function that fires when a drag gesture starts. Provided the triggering PointerEvent and info.

<motion.div drag onDragStart={(event, info) => console.log(info.delta.x)} />

onDragEnd

Callback function that fires when a drag gesture ends. Provided the triggering PointerEvent and info.

<motion.div drag onDragEnd={(event, info) => console.log(info.delta.x)} />

onDirectionLock

Callback function that fires a drag direction is determined.

<motion.div
  drag
  dragDirectionLock
  onDirectionLock={axis => console.log(axis)}
/>

Viewport

whileInView

Target or variants to label to while the element is in view.

// As target
<motion.div whileInView={{ opacity: 1 }} />
// As variants
<motion.div whileInView="visible" />

viewport

Options to define how the element is tracked within the viewport.

<motion.section
  whileInView={{ opacity: 1 }}
  viewport={{ once: true }}
/>

Available options:

  • once: If true, once element enters the viewport it won't detect subsequent leave/enter events.

  • root: The ref of an ancestor scrollable element to detect intersections with (instead of window).

  • margin: A margin to add to the viewport to change the detection area. Defaults to "0px". Use multiple values to adjust top/right/bottom/left, e.g. "0px -20px 0px 100px".

  • amount: The amount of an element that should enter the viewport to be considered "entered". Either "some", "all" or a number between 0 and 1. Defaults to "some".

onViewportEnter

Callback function that fires when an element enters the viewport. Provided the IntersectionObserverEntry with details of the intersection event.

<motion.div onViewportEnter={(entry) => console.log(entry.isIntersecting)} />

onViewportLeave

Callback function that fires when an element enters the viewport. Provided the IntersectionObserverEntry with details of the intersection event.

<motion.div onViewportLeave={(entry) => console.log(entry.intersectionRect)} />

Layout

layout

Default: false

If true, this component will animate changes to its layout.

<motion.div layout />

If set to "position" or "size", only its position or size will animate, respectively.

<motion.img layout="position" />

layoutId

If set, this component will animate changes to its layout. Additionally, when a new element enters the DOM and an element already exists with a matching layoutId, it will animate out from the previous element's size/position.

{items.map(item => (
   <motion.li layout>
      {item.name}
      {item.isSelected && <motion.div layoutId="underline" />}
   </motion.li>
))}

If the previous component remains in the tree, the two elements will crossfade.

layoutDependency

By default, layout changes are detected every render. To reduce measurements and thus improve performance, you can pass a layoutDependency prop. Measurements will only occur when this value changes.

<motion.nav layout layoutDependency={isOpen} />

layoutScroll

For layout animations to work correctly within scrollable elements, their scroll offset needs measuring. For performance reasons, Framer Motion doesn't measure the scroll offset of every ancestor. Add the layoutScroll prop to elements that should be measured.

<motion.div layoutScroll style={{ overflow: "scroll" }}>
  <motion.div layout />
</motion.div>

layoutRoot

For layout animations to work correctly within position: fixed elements, we need to account for page scroll. Add layoutRoot to mark an element as position: fixed.

<motion.div layoutRoot style={{ position: "fixed" }}>
  <motion.div layout />
</motion.div>

onLayoutAnimationStart

A callback to run when a layout animation starts.

onLayoutAnimationComplete

A callback to run when a layout animation completes.

Advanced

inherit

Set to false to prevent a component inheriting or propagating changes in a parent variant.

custom

Custom data to pass through to dynamic variants.

const variants = {
  visible: (custom) => ({
    opacity: 1,
    transition: { delay: custom * 0.2 }
  })
}

return (
  <motion.ul animate="visible">
    <motion.li custom={0} variants={variants} />
    <motion.li custom={1} variants={variants} />
    <motion.li custom={2} variants={variants} />
  </motion.ul>
)

transformTemplate

By default, transforms are applied in order of translate, scale, rotate and skew.

To change this, transformTemplate can be set as a function that accepts the latest transforms and the generated transform string and returns a new transform string.

// Use the latest transform values
<motion.div
  style={{ x: 0, rotate: 180 }}
  transformTemplate={
    ({ x, rotate }) => `rotate(${rotate}deg) translateX(${x}px)`
  }
/>
// Or the generated transform string
<motion.div
  style={{ x: 0, rotate: 180 }}
  transformTemplate={
    (latest, generated) => `translate(-50%, -50%) ${generated}`
  }
/>

A Motion+ membership will give you early access to features & content, access to our private Github and Discord, and more.

It's a one-time fee that grants lifetime access. No subscription necessary!

MOTION+

Introducing Cursor

Cursor is a creative cursor component for React, that makes it super easy to make custom cursor and follow cursor effects.


Hover over these examples to check out some of what it can do:

Custom cursor

Follow with spring

Multicursor

?

?