Edit Page

#Motion components

Motion components are DOM primitives optimised for 60fps animation and gestures.

There's a motion component for every HTML and SVG element, for instance motion.div, motion.circle etc.

These work exactly like their static counterparts, but offer props that allow you to:

  • Declaratively or imperatively animate components.
  • Add drag, pan, hover and tap gestures.
  • Respond to gestures with animations.
  • Deeply animate throughout React trees via variants.
import { motion } from "framer-motion"

export const MyComponent () => (
  <motion.div
    animate={{ rotate: 360 }}
    transition={{ duration: 2 }}
  />
)

#Supported values

#Value types

Motion can animate:

  • Numbers: 0, 10 etc.
  • Strings containing numbers: "0vh", "10px" etc.
  • Colors: Hex, RGB(A), HSL(A).
  • Complex strings containing multiple numbers and/or colors (ie "10px 0 #000")

When animating to a non-animatable value like "block", this value will be set instantly. By setting this value within transitionEnd, this value will be set at the end of the animation.

<motion.div
  animate={{
    x: 0,
    backgroundColor: "#000",
    boxShadow: "10px 10px 0 rgba(0, 0, 0, 0.2)",
    position: "fixed",
    transitionEnd: {
      display: "none",
    },
  }}
/>

#Value type conversion

In general, values can only be animated between two of the same type (ie two HSL(A), two px etc).

However, HTML component's x, y, width, height, top, left, right and bottom values have enhanced support and can all be animated freely between different value types.

<motion.div
  initial={{ x: "100%" }}
  animate={{ x: "calc(100vw - 50%)" }}
/>

#Transform

Transform properties are accelerated by the GPU, and therefore animate smoothly. They can be set and animated individually as:

  • Translate shortcuts: x, y, z
  • Translate: translateX, translateY, translateZ
  • Scale: scale, scaleX, scaleY
  • Rotate: rotate, rotateX, rotateY, rotateZ
  • Skew: skew, skewX, skewY
<motion.a
  whileHover={{ scale: 1.2 }}
  whilePress={{ scale: 0.8 }}
  style={{ x: 100 }}
/>

motion components have enhanced style props, allowing you to set them individually there, too.

For convenience, transform values are applied in a specific order: translate, scale, rotate, skew.

However, you can customise this default order using the transformTemplate prop.

function template({ rotate, x }) {
  return `rotate(${rotate}deg) translateX(${x}px)`
}

return (
  <motion.div
    transformTemplate={template}
    animate={{ rotate: 360 }}
    style={{ rotate: 0, x: "calc(50vh - 100px)" }}
  />
)

SVG note: For SVG components, x and y are positional attributes distinct from translateX and translateY. Using the former will change the element's x/y attributes, while using the latter will set its style.transform property.

#Transform origin

transform-origin has three shortcut values that can be set and animated individually:

  • originX
  • originY
  • originZ

If set as numbers, originX and Y default to a progress value between 0 and 1. originZ defaults to pixels.

<motion.div style={{ originX: 0.5 }} />

#CSS variables

Motion can animate the value of CSS variables, and also read CSS variables as animation targets.

#Using pre-defined CSS variables in animation

HTML motion components can animate to and from CSS variables, as long as that variable is defined on a component ancestor.

<motion.li animate={{ background: "var(--action)" }} />

#Animating CSS variables

By defining and animating CSS variables, we can use a parent motion component to declaratively animate multiple DOM children.

When animating CSS variables in TypeScript, the prop will need to be cast as any to prevent type errors (as there's an infinite number of variable names).

CSS variables are also of an arbitary type, so Motion can't infer their default type. You're able to animate rotate as a number because Motion understands that it should be set as deg, whereas '--rotate' needs to be explicitly set with the unit type, e.g. '360deg'.

<motion.ul
  initial={{ '--rotate': '0deg' } as any}
  animate={{ '--rotate': '360deg' } as any}
  transition={{ duration: 2, loop: Infinity }}
>
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
</motion.ul>

#SVG path

motion.path components have access to three convenience SVG path properties:

  • pathLength
  • pathSpacing
  • pathOffset

These are all set as a value between 0 and 1, where 1 is the measured length of the path.

<motion.path
  d={pathDefinition}
  initial={{ pathLength: 1, pathOffset: 0 }}
  animate={{ pathLength: 0, pathOffset: 1 }}
  transition={{ duration: 2 }}
/>

#Performance

Motion animates values outside the React render cycle for increased performance.

Using MotionValues instead of state to update visual properties will also avoid re-renders.

Where possible, animate just transform values and opacity, as they are GPU-accelerated. This way, you can animate hundreds of layers on modern mobile devices.

// GPU accelerated (fast)
<motion.div style={{ x: 0 }} animate={{ x: 100 }} />

// CPU drawing (slower)
<motion.div style={{ left: 0 }} animate={{ left: 100 }} />

#Server-side rendering

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

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

#Exceptions

The following SVG values are not currently compatible with server-side rendering: scale, rotate, pathLength, pathOffset and pathSpacing.

scale and rotate rely on the dynamic calculation of transformOrigin - originX and originY should be set as strings (either px or %) to support these server side.

<motion.circle
  style={{ scale: 2, originX: "100px", originY: "100px" }}
/>

path values rely on the measurement of the overall path length. Setting strokeDasharray to "0 1" will hide the path until Motion can measure it.

<motion.path strokeDasharray="0 1" />

#Props

motion components accept the following props:

#style: MotionStyle

The React DOM style prop, enhanced with support for MotionValues and separate transform values.

export const MyComponent = () => {
  const x = useMotionValue(0)

  return <motion.div style={{ x, opacity: 1, scale: 0.5 }} />
}

#initial: boolean | Target | VariantLabels

Properties, variant label or array of variant labels to start in.

Set to false to initialise with the values in animate (disabling the mount animation)

// As values
<motion.div initial={{ opacity: 1 }} />

// As variant
<motion.div initial="visible" variants={variants} />

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

// As false (disable mount animation)
<motion.div initial={false} animate={{ opacity: 0 }} />

#animate: AnimationControls | TargetAndTransition | VariantLabels

Values to animate to, variant label(s), or AnimationControls.

// As values
<motion.div animate={{ opacity: 1 }} />

// As variant
<motion.div animate="visible" variants={variants} />

// Multiple variants
<motion.div animate={["visible", "active"]} variants={variants} />

// AnimationControls
<motion.div animate={animation} />

#exit: AnimationControls | TargetAndTransition | VariantLabels

A target to animate to when this component is removed from the tree.

This component **must** be the first animatable child of an AnimatePresence to enable this exit animation.

This limitation exists because React doesn't allow components to defer unmounting until after an animation is complete. Once this limitation is fixed, the AnimatePresence component will be unnecessary.

import { AnimatePresence, motion } from 'framer-motion'

export const MyComponent = ({ isVisible }) => {
  return (
    <AnimatePresence>
       {isVisible && (
         <motion.div
           initial={{ opacity: 0 }}
           animate={{ opacity: 1 }}
           exit={{ opacity: 0 }}
         />
       )}
    </AnimatePresence>
  )
}

#transition: Transition

Default transition. If no transition is defined in animate, it will use the transition defined here.

const spring = {
  type: "spring",
  damping: 10,
  stiffness: 100
}

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

#variants: Variants

Variants allow you to define animation states and organise them by name. They allow you to control animations throughout a component tree by switching a single animate prop.

Using transition options like delayChildren and staggerChildren, you can orchestrate when children animations play relative to their parent.

After passing variants to one or more motion component's variants prop, these variants can be used in place of values on the animate, initial, whileTap and whileHover props.

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

<motion.div variants={variants} animate="active" />

#positionTransition: Transition | boolean | ResolveLayoutTransition

If positionTransition is defined on a motion component, it will automatically animate any changes to its layout using a performant x/y transform.

positionTransition can either be set as a Transition, or just true to use the default position transition, which is a snappy spring.

It can also be set as a function that will resolve when the component has changed layout. This function should return either a Transition, or true. For advanced use-cases where you want the component to visually stay in its previous position, this function can also return false. This function will receive the delta of the changed layout.

const spring = {
  type: "spring",
  damping: 10,
  stiffness: 100
}

// This component will animate position when `isVisible` is toggled.
const MyComponent = ({ isOpen }) => {
  return (
    <motion.div positionTransition={spring} style={{ left: isOpen ? 0 : 100 }} />
  )
}

// This component will animate items to their new position if its place in `items` changes order.
const MyComponent = ({ items }) => {
  return items.map((item) => (
    <motion.div key={item.id} positionTransition={spring} />
  ))
}

#layoutTransition: Transition | boolean | ResolveLayoutTransitionBeta

If layoutTransition is defined on a motion component, the component will automatically animate any changes to its position **and** size.

It will do so using performant transforms. So if a motion component changes position, it'll animate to its new position using x and y. If it changes size, it'll animate using scaleX and scaleY.

Animating size with scale can introduce visual distortion to the component's children. If unwanted, the useInvertedScale function can be used to undo this distortion.

layoutTransition can either be set as a Transition, or just true to use the default layout transition, which is a smooth 0.8 second ease.

It can also be set as a function that will resolve when the component has changed layout. This function should return either a Transition, or true. For advanced use-cases where you want the component to visually stay in its previous position, this function can also return false. This function will receive the delta of the changed layout.

const spring = {
  type: "spring",
  damping: 10,
  stiffness: 100
}

// This component will animate between sizes when `isVisible` is toggled.
const MyComponent = ({ isVisible }) => {
  return (
    <motion.div layoutTransition={spring}>
      {isVisible && <Content />}
    </motion.div>
  )
}

#custom: any

Custom data to use to resolve dynamic variants differently for each animating component.

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

<motion.div custom={0} animate="visible" variants={variants} />
<motion.div custom={1} animate="visible" variants={variants} />
<motion.div custom={2} animate="visible" variants={variants} />

#transformTemplate(transform, generatedTransform): string

By default, Framer Motion generates a transform property with a sensible transform order. transformTemplate can be used to create a different order, or to append/preprend the automatically generated transform property.

<motion.div
  style={{ x: 0, rotate: 180 }}
  transformTemplate={
    ({ x, rotate }) => `rotate(${rotate}deg) translateX(${x}px)`
  }
/>
transform: TransformProperties

The latest animated transform props.

generatedTransform: string

The transform string as automatically generated by Framer Motion

returns: string

#onUpdate(latest): void

Callback with latest motion values, fired max once per frame.

function onUpdate(latest) {
  console.log(latest.x, latest.opacity)
}

<motion.div animate={{ x: 100, opacity: 0 }} onUpdate={onUpdate} />
latest: { [key: string]: string | number; }

#onAnimationStart(): void

Callback when animation defined in animate begins.

function onStart() {
  console.log("Animation completed")
}

<motion.div animate={{ x: 100 }} onAnimationStart={onStart} />

#onAnimationComplete(): void

Callback when animation defined in animate is complete.

function onComplete() {
  console.log("Animation completed")
}

<motion.div animate={{ x: 100 }} onAnimationComplete={onComplete} />

#whileHover: string | TargetAndTransition

Properties or variant label to animate to while the hover gesture is recognised.

<motion.div whileHover={{ scale: 1.2 }} />

#whileTap: string | TargetAndTransition

Properties or variant label to animate to while the component is pressed.

<motion.div whileTap={{ scale: 0.8 }} />

#onHoverStart(event, info): void

Callback function that fires when pointer starts hovering over the component.

<motion.div onHoverStart={() => console.log('Hover starts')} />
event: MouseEvent
info: EventInfo

#onHoverEnd(event, info): void

Callback function that fires when pointer stops hovering over the component.

<motion.div onHoverEnd={() => console.log("Hover ends")} />
event: MouseEvent
info: EventInfo

#onTap(event, info): void

Callback when the tap gesture successfully ends on this element.

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

<motion.div onTap={onTap} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: TapInfo

An TapInfo object containing x and y values for the point relative to the device or page.

#onTapStart(event, info): void

Callback when the tap gesture starts on this element.

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

<motion.div onTapStart={onTapStart} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: TapInfo

An TapInfo object containing x and y values for the point relative to the device or page.

#onTapCancel(event, info): void

Callback when the tap gesture ends outside this element.

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

<motion.div onTapCancel={onTapCancel} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: TapInfo

An TapInfo object containing x and y values for the point relative to the device or page.

#onPan(event, info): void

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

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

<motion.div onPan={onPan} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: PanInfo

A PanInfo object containing x and y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.

#onPanStart(event, info): void

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

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

<motion.div onPanStart={onPanStart} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: PanInfo

A PanInfo object containing x/y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.

#onPanEnd(event, info): void

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

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

<motion.div onPanEnd={onPanEnd} />
event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event.

info: PanInfo

A PanInfo object containing x/y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.

#onDrag(event, info): void

Callback function that fires when the component is dragged.

<motion.div
  drag
  onDrag={
    (event, info) => console.log(info.point.x, info.point.y)
  }
/>
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo

#onDragStart(event, info): void

Callback function that fires when dragging starts.

<motion.div
  drag
  onDragStart={
    (event, info) => console.log(info.point.x, info.point.y)
  }
/>
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo

#onDragEnd(event, info): void

Callback function that fires when dragging ends.

<motion.div
  drag
  onDragEnd={
    (event, info) => console.log(info.point.x, info.point.y)
  }
/>
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo

#onDirectionLock(axis): void

Callback function that fires a drag direction is determined.

<motion.div
  drag
  dragDirectionLock
  onDirectionLock={axis => console.log(axis)}
/>
axis: "x" | "y"

#drag: boolean | "x" | "y"

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

<motion.div drag="x" />

#dragConstraints: false | { top?: number; right?: number; bottom?: number; left?: number; } | RefObject<Element>

An object of optional top, left, right, bottom pixel values, beyond which dragging is constrained.

Another component can be used as drag constraints by creating a ref with React's useRef.hook. This ref should be passed to that component's ref prop and to this component's dragConstraints prop.

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

// As a ref to another component
const MyComponent = () => {
  const constraintsRef = useRef(null)

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

#dragElastic: boolean | number

The degree of movement allowed outside constraints. 0 = no movement, 1 = full movement. Set to 0.5 by default.

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

#dragMomentum: boolean

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: InertiaOptions

Allows you to change dragging inertia parameters. When releasing a draggable Frame, an animation with type inertia starts. The animation is based on your dragging velocity. This property allows you to customize it. See Inertia for all properties you can use.

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

#dragPropagation: boolean

Allows drag gesture propagation to child components. Set to false by default.

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