W↓
All docs
🔑
Sign Up/Sign In
motion.dev/docs/react-
Public Link
Apr 8, 2025, 12:33:40 PM - complete - 424 kB
Apr 8, 2025, 12:33:39 PM - complete - 424 kB
Apr 8, 2025, 12:28:36 PM - complete - 427.2 kB
Starting URLs:
https://motion.dev/docs/react-quick-start
CSS Selector:
article
Crawl Prefixes:
https://motion.dev/docs/react-
Exclude Patterns:
https://motion.dev/docs/react-courses
## Page: https://motion.dev/docs/react-quick-start # Get started with Motion for React Motion for React is an animation library that's simple to start and fun to master. It's the only library with a **hybrid engine**. This means it offers both the hardware accelerated performance of native browser animations, coupled with the limitless potential of JavaScript animations. It's also trusted by Framer to power its amazing no-code animations and gestures. In this guide, we'll learn how to install Motion and take a whirlwind tour of its main features. ## Install Motion is available via npm: npm install motion Features can now be imported via `"motion/react"`: import { motion } from "motion/react" **Note:** Motion for React contains APIs specifically tailored for React, but every feature from vanilla Motion is also compatible and available for advanced use-cases. ## Usage The core of Motion for React is the `<motion />` component. It's a normal DOM element, supercharged with animation capabilities. <motion.div /> Animating a `motion` component is as straightforward as setting values via the `animate` prop: <motion.ul animate\={{ rotate: 360 }} /> When values in `animate` change, the component will animate. Motion has intuitive defaults, but animations can of course be configured via the `transition` prop. <motion.div animate\={{ scale: 2, transition: { duration: 2 } }} /> ### Enter animation When a component enters the page, it will automatically animate to the values defined in the `animate` prop. You can provide values to animate from via the `initial` prop, otherwise these will be read from the DOM. <motion.button initial\={{ scale: 0 }} animate\={{ scale: 1 }} /> Or disable this initial animation entirely by setting `initial` to `false`. <motion.button initial\={false} animate\={{ scale: 1 }} /> ### Gestures `<motion />` extends React's event system with powerful gesture recognisers. It currently supports hover, tap, focus, and drag. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.95 }} onHoverStart\={() \=> console.log('hover started!')} /> Motion's gestures are designed to feel better than using CSS or JavaScript events alone. Learn more about Motion's gestures. ### Scroll animations Motion supports both types of scroll animations, **scroll-triggered** and **scroll-linked**. To trigger an animation on scroll, the `whileInView` prop defines a state to animate to/from when an element enters/leaves the viewport: <motion.div initial\={{ backgroundColor: "rgb(0, 255, 0)", opacity: 0 }} whileInView\={{ backgroundColor: "rgb(255, 0, 0)", opacity: 1 }} /> Whereas to link a value directly to scroll position, it's possible to use `MotionValue`s via `useScroll`. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> Learn more about Motion's scroll animations. ### Layout animations Motion has an industry-leading layout animation engine that supports animating between changes in layout, using only transforms, between the same or different elements, with full scale correction. It's as easy as applying the `layout` prop. <motion.div layout /> Or to animate between different elements, a `layoutId`: <motion.div layoutId\="underline" /> Learn more about layout animations. ### Exit animations Animating elements when they're removed from the DOM is usually messy. By wrapping `motion` components with `<AnimatePresence>` we gain access to the `exit` prop. <AnimatePresence\> {show ? <motion.div key\="box" exit\={{ opacity: 0 }} /> : null} </AnimatePresence\> Learn more about `AnimatePresence`. ## Learn next That's a very quick overview of Motion for React's basic features. But there's a lot more to learn! Next, we recommend diving further into the the `<motion />` component to learn more about its powerful features, like variants. Or, you can dive straight in to our Fundamentals examples. Each comes complete with full source code that you can copy/paste into your project. Motion for React is an animation library that's simple to start and fun to master. It's the only library with a **hybrid engine**. This means it offers both the hardware accelerated performance of native browser animations, coupled with the limitless potential of JavaScript animations. It's also trusted by Framer to power its amazing no-code animations and gestures. In this guide, we'll learn how to install Motion and take a whirlwind tour of its main features. ## Install Motion is available via npm: npm install motion Features can now be imported via `"motion/react"`: import { motion } from "motion/react" **Note:** Motion for React contains APIs specifically tailored for React, but every feature from vanilla Motion is also compatible and available for advanced use-cases. ## Usage The core of Motion for React is the `<motion />` component. It's a normal DOM element, supercharged with animation capabilities. <motion.div /> Animating a `motion` component is as straightforward as setting values via the `animate` prop: <motion.ul animate\={{ rotate: 360 }} /> When values in `animate` change, the component will animate. Motion has intuitive defaults, but animations can of course be configured via the `transition` prop. <motion.div animate\={{ scale: 2, transition: { duration: 2 } }} /> ### Enter animation When a component enters the page, it will automatically animate to the values defined in the `animate` prop. You can provide values to animate from via the `initial` prop, otherwise these will be read from the DOM. <motion.button initial\={{ scale: 0 }} animate\={{ scale: 1 }} /> Or disable this initial animation entirely by setting `initial` to `false`. <motion.button initial\={false} animate\={{ scale: 1 }} /> ### Gestures `<motion />` extends React's event system with powerful gesture recognisers. It currently supports hover, tap, focus, and drag. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.95 }} onHoverStart\={() \=> console.log('hover started!')} /> Motion's gestures are designed to feel better than using CSS or JavaScript events alone. Learn more about Motion's gestures. ### Scroll animations Motion supports both types of scroll animations, **scroll-triggered** and **scroll-linked**. To trigger an animation on scroll, the `whileInView` prop defines a state to animate to/from when an element enters/leaves the viewport: <motion.div initial\={{ backgroundColor: "rgb(0, 255, 0)", opacity: 0 }} whileInView\={{ backgroundColor: "rgb(255, 0, 0)", opacity: 1 }} /> Whereas to link a value directly to scroll position, it's possible to use `MotionValue`s via `useScroll`. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> Learn more about Motion's scroll animations. ### Layout animations Motion has an industry-leading layout animation engine that supports animating between changes in layout, using only transforms, between the same or different elements, with full scale correction. It's as easy as applying the `layout` prop. <motion.div layout /> Or to animate between different elements, a `layoutId`: <motion.div layoutId\="underline" /> Learn more about layout animations. ### Exit animations Animating elements when they're removed from the DOM is usually messy. By wrapping `motion` components with `<AnimatePresence>` we gain access to the `exit` prop. <AnimatePresence\> {show ? <motion.div key\="box" exit\={{ opacity: 0 }} /> : null} </AnimatePresence\> Learn more about `AnimatePresence`. ## Learn next That's a very quick overview of Motion for React's basic features. But there's a lot more to learn! Next, we recommend diving further into the the `<motion />` component to learn more about its powerful features, like variants. Or, you can dive straight in to our Fundamentals examples. Each comes complete with full source code that you can copy/paste into your project. Motion for React is an animation library that's simple to start and fun to master. It's the only library with a **hybrid engine**. This means it offers both the hardware accelerated performance of native browser animations, coupled with the limitless potential of JavaScript animations. It's also trusted by Framer to power its amazing no-code animations and gestures. In this guide, we'll learn how to install Motion and take a whirlwind tour of its main features. ## Install Motion is available via npm: npm install motion Features can now be imported via `"motion/react"`: import { motion } from "motion/react" **Note:** Motion for React contains APIs specifically tailored for React, but every feature from vanilla Motion is also compatible and available for advanced use-cases. ## Usage The core of Motion for React is the `<motion />` component. It's a normal DOM element, supercharged with animation capabilities. <motion.div /> Animating a `motion` component is as straightforward as setting values via the `animate` prop: <motion.ul animate\={{ rotate: 360 }} /> When values in `animate` change, the component will animate. Motion has intuitive defaults, but animations can of course be configured via the `transition` prop. <motion.div animate\={{ scale: 2, transition: { duration: 2 } }} /> ### Enter animation When a component enters the page, it will automatically animate to the values defined in the `animate` prop. You can provide values to animate from via the `initial` prop, otherwise these will be read from the DOM. <motion.button initial\={{ scale: 0 }} animate\={{ scale: 1 }} /> Or disable this initial animation entirely by setting `initial` to `false`. <motion.button initial\={false} animate\={{ scale: 1 }} /> ### Gestures `<motion />` extends React's event system with powerful gesture recognisers. It currently supports hover, tap, focus, and drag. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.95 }} onHoverStart\={() \=> console.log('hover started!')} /> Motion's gestures are designed to feel better than using CSS or JavaScript events alone. Learn more about Motion's gestures. ### Scroll animations Motion supports both types of scroll animations, **scroll-triggered** and **scroll-linked**. To trigger an animation on scroll, the `whileInView` prop defines a state to animate to/from when an element enters/leaves the viewport: <motion.div initial\={{ backgroundColor: "rgb(0, 255, 0)", opacity: 0 }} whileInView\={{ backgroundColor: "rgb(255, 0, 0)", opacity: 1 }} /> Whereas to link a value directly to scroll position, it's possible to use `MotionValue`s via `useScroll`. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> Learn more about Motion's scroll animations. ### Layout animations Motion has an industry-leading layout animation engine that supports animating between changes in layout, using only transforms, between the same or different elements, with full scale correction. It's as easy as applying the `layout` prop. <motion.div layout /> Or to animate between different elements, a `layoutId`: <motion.div layoutId\="underline" /> Learn more about layout animations. ### Exit animations Animating elements when they're removed from the DOM is usually messy. By wrapping `motion` components with `<AnimatePresence>` we gain access to the `exit` prop. <AnimatePresence\> {show ? <motion.div key\="box" exit\={{ opacity: 0 }} /> : null} </AnimatePresence\> Learn more about `AnimatePresence`. ## Learn next That's a very quick overview of Motion for React's basic features. But there's a lot more to learn! Next, we recommend diving further into the the `<motion />` component to learn more about its powerful features, like variants. Or, you can dive straight in to our Fundamentals examples. Each comes complete with full source code that you can copy/paste into your project. --- ## Page: https://motion.dev/docs/react-animation # React animation Motion for React offers a number of ways to animate your UI. Scaling from extremely simple prop-based animations, to more complex orchestration. ## Basic animations You'll perform almost all animations on a `<motion />` component. This is basically a DOM element with motion superpowers. import { motion } from "motion/react" For basic animations, you can update values on the `animate` prop: <motion.div animate\={{ opacity: 1 }} /> When any value in its animate prop changes, the component will automatically animate to the new target. ## Animatable values Motion can animate any CSS value, even those that can't be animated by browsers, like `mask-image`. It supports: * Numbers: `0`, `100` etc. * Strings containing numbers: `"0vh"`, `"10px"` etc. * Colors: Hex, RGBA, HSLA. * Complex strings containing multiple numbers and/or colors (like `box-shadow`). * `display: "none"/"block"` and `visibility: "hidden"/"visible"`. ### Value type conversion In general, values can only be animated between two of the same type (i.e `"0px"` to `"100px"`). Colors can be freely animated between hex, RGBA and HSLA types. Additionally, `x`, `y`, `width`, `height`, `top`, `left`, `right` and `bottom` can animate between different value types. <motion.div initial\={{ x: "100%" }} animate\={{ x: "calc(100vw - 50%)" }} /> It's also possible to animate `width` and `height` in to/out of `"auto"`. <motion.div initial\={{ height: 0 }} animate\={{ height: "auto" }} /> **Note:** If additionally animating `display` in to/out of `"none"`, replace this with `visibility` `"hidden"` as elements with `display: none` can't be measured. ### Transforms Unlike CSS, Motion can animate every transform axis independently: * Translate: `x`, `y`, `z` * Scale: `scale`, `scaleX`, `scaleY` * Rotate: `rotate`, `rotateX`, `rotateY`, `rotateZ` * Skew: `skew`, `skewX`, `skewY` * Perspective: `transformPerspective` `motion` components have enhanced `style` props, allowing you to set individual transforms: <motion.section style\={{ x: -20 }} /> Animating transforms independently provides great flexibility, especially around gestures. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} /> Independent transforms perform great, but Motion's hybrid engine also uniquely offers hardware acceleration by setting `transform` directly. <motion.li initial\={{ transform: "translateX(-100px)" }} animate\={{ transform: "translateX(0px)" }} transition\={{ type: "spring" }} /> **SVG note:** For SVG components, `x` and `y` **attributes** can be set using `attrX` and `attrY`. ### 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 for React can animate the value of CSS variables, and also use CSS variables as animation targets. #### Animating CSS variables Sometimes it's convenient to be able to animate a CSS variable to animate many children: <motion.ul initial\={{ '--rotate': '0deg' }} animate\={{ '--rotate': '360deg' }} transition\={{ duration: 2, repeat: Infinity }} \> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> </motion.ul\> **Note:** Animating the value of a CSS variable **always triggers paint**, therefore it can be more performant to use `MotionValue`s to setup this kind of animation. ### CSS variables as animation targets HTML `motion` components accept animation targets with CSS variables: <motion.li animate\={{ backgroundColor: "var(--action-bg)" }} /> #### SVG line drawing Line drawing animations can be created with many different SVG elements using three special properties: `pathLength`, `pathSpacing` and `pathOffset`. <motion.path initial\={{ pathLength: 0 }} animate\={{ pathLength: 1 }} /> All three are set as a progress value between `0` and `1`, `1` representing the total length of the path. Path animations are compatible with `circle`, `ellipse`, `line`, `path`, `polygon`, `polyline` and `rect` elements. ## Transitions By default, Motion will create appropriate transitions for snappy animations based on the type of value being animated. For instance, physical properties like `x` or `scale` are animated with spring physics, whereas values like `opacity` or `color` are animated with duration-based easing curves. However, you can define your own animations via the `transition` prop. <motion.div animate\={{ x: 100 }} transition\={{ ease: "easeOut", duration: 2 }} /> ## Enter animations When a `motion` component is first created, it'll automatically animate to the values in `animate` if they're different from those initially rendered, which you can either do via CSS or via the `initial` prop. <motion.li initial\={{ opacity: 0, scale: 0 }} animate\={{ opacity: 1, scale: 1 }} /> You can also disable the enter animation entirely by setting `initial={false}`. This will make the element render with the values defined in `animate`. <motion.div initial\={false} animate\={{ y: 100 }} /> ## Exit animations You can also easily animate elements as they exit the DOM. In React, when a component is removed, it's usually removed instantly. Motion provides the `AnimatePresence` component which keeps elements in the DOM while they perform an `exit` animation. <AnimatePresence\> {isVisible && ( <motion.div key\="modal" initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} /> )} </AnimatePresence\> ## Keyframes Values in `animate` can be set as a series of keyframes. This will animate through each value in sequence. <motion.div animate\={{ x: \[0, 100, 0\] }} /> We can use a value's current state as the initial keyframe by setting it to `null`. <motion.div animate\={{ x: \[null, 100, 0\] }} /> This way, if a keyframe animation is interrupting another animation, the transition will feel more natural. By default, each keyframe is spaced naturally throughout the animation. You can override this by setting the `times` option via `transition`. `times` is an array of progress values between `0` and `1`, defining where in the animation each keyframe should be positioned. <motion.circle cx\={500} animate\={{ cx: \[null, 100, 200\], transition: { duration: 3, times: \[0, 0.2, 1\] } }} /> ## Gesture animations Motion for React has shortcut props for animating to/from a target when a gesture starts/ends. <motion.button initial\={{ opacity: 0 }} whileHover\={{ backgroundColor: "rgba(220, 220, 220, 1)" }} whileTap\={{ backgroundColor: "rgba(255, 255, 255, 1)" }} whileInView\={{ opacity: 1 }} /> It supports `hover`, `tap`, `drag`, `focus` and `inView`. ## Variants Setting `animate` as a target is useful for simple, single-element animations. But sometimes we want to orchestrate animations that propagate throughout the DOM. We can do so with variants. Variants are a set of named targets. const variants = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } They're passed to `motion` components via the `variants` prop: <motion.div variants\={variants} /> These variants can now be referred to by a label, wherever you can define an animation target: <motion.div variants\={variants} initial\="hidden" whileInView\="visible" /> You can also define multiple variants via an array: animate\={\["visible", "danger"\]} > _I love using variants alongside React state – just pass your state to_ `_animate_`_, and now you've got a tidy place to define all your animation targets!_ > > const \[status, setStatus\] = useState<"inactive" | "active" | "complete"\>( > "inactive" > ); > > <motion.div > animate\={status} // pass in our React state! > variants\={{ > inactive: { scale: 0.9 color: "var(--gray-500)" }, > active: { scale: 1 color: "var(--blue-500)" }, > complete: { scale: 1 color: "var(--blue-500)" } > }} > \> > <motion.svg > path\={checkmarkPath} > variants\={{ > inactive: { pathLength: 0 }, > active: { pathLength: 0 }, > complete: { pathLength: 1} > }} > /> > </motion.div\> > > ~ Sam Selikoff, Motion for React Recipes ### Propagation This is already useful for reusing and combining animation targets. But it becomes powerful for orchestrating animations throughout trees. Variants will flow down through `motion` components. So in this example when the `ul` enters the viewport, all of its children with a "visible" variant will also animate in: const list = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } const item = { visible: { opacity: 1, x: 0 }, hidden: { opacity: 0, x: -100 }, } return ( <motion.ul initial\="hidden" whileInView\="visible" variants\={list} \> <motion.li variants\={item} /> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) ### Orchestration By default, this children animations will start simultaneously with the parent. But with variants we gain access to new `transition` props like `when`, `delayChildren`, `staggerChildren` and `staggerDirection`. const list = { visible: { opacity: 1, transition: { when: "beforeChildren", staggerChildren: 0.3, // Stagger children by .3 seconds }, }, hidden: { opacity: 0, transition: { when: "afterChildren", }, }, } ### Dynamic variants Each variant can be defined as a function that resolves when a variant is made active. const variants = { hidden: { opacity: 0 }, visible: (index) \=> ({ opacity: 1, transition: { delay: index \* 0.3 } }) } These functions are provided a single argument, which is passed via the `custom` prop: items.map((item, index) \=> <motion.div custom\={index} variants\={variants} />) This way, variants can be resolved differently for each animating element. ## Animation controls Declarative animations are ideal for most UI interactions. But sometimes we need to take manual control over animation playback. The `useAnimate` hook can be used for: * Animating any HTML/SVG element (not just `motion` components). * Complex animation sequences. * Controlling animations with `time`, `speed`, `play()`, `pause()` and other playback controls. function MyComponent() { const \[scope, animate\] = useAnimate() useEffect(() \=> { const controls = animate(\[ \[scope.current, { x: "100%" }\], \["li", { opacity: 1 }\] \]) controls.speed = 0.8 return () \=> controls.stop() }, \[\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ## Animate content By passing a `MotionValue` as the child of a `motion` component, it will render its latest value in the HTML. import { useMotionValue, motion, animate } from "motion/react" function Counter() { const count = useMotionValue(0) useEffect(() \=> { const controls = animate(count, 100, { duration: 5 }) return () \=> controls.stop() }, \[\]) return <motion.pre\>{count}</motion.pre\> } This is more performant than setting React state as the `motion` component will set `innerHTML` directly. Motion for React offers a number of ways to animate your UI. Scaling from extremely simple prop-based animations, to more complex orchestration. ## Basic animations You'll perform almost all animations on a `<motion />` component. This is basically a DOM element with motion superpowers. import { motion } from "motion/react" For basic animations, you can update values on the `animate` prop: <motion.div animate\={{ opacity: 1 }} /> When any value in its animate prop changes, the component will automatically animate to the new target. ## Animatable values Motion can animate any CSS value, even those that can't be animated by browsers, like `mask-image`. It supports: * Numbers: `0`, `100` etc. * Strings containing numbers: `"0vh"`, `"10px"` etc. * Colors: Hex, RGBA, HSLA. * Complex strings containing multiple numbers and/or colors (like `box-shadow`). * `display: "none"/"block"` and `visibility: "hidden"/"visible"`. ### Value type conversion In general, values can only be animated between two of the same type (i.e `"0px"` to `"100px"`). Colors can be freely animated between hex, RGBA and HSLA types. Additionally, `x`, `y`, `width`, `height`, `top`, `left`, `right` and `bottom` can animate between different value types. <motion.div initial\={{ x: "100%" }} animate\={{ x: "calc(100vw - 50%)" }} /> It's also possible to animate `width` and `height` in to/out of `"auto"`. <motion.div initial\={{ height: 0 }} animate\={{ height: "auto" }} /> **Note:** If additionally animating `display` in to/out of `"none"`, replace this with `visibility` `"hidden"` as elements with `display: none` can't be measured. ### Transforms Unlike CSS, Motion can animate every transform axis independently: * Translate: `x`, `y`, `z` * Scale: `scale`, `scaleX`, `scaleY` * Rotate: `rotate`, `rotateX`, `rotateY`, `rotateZ` * Skew: `skew`, `skewX`, `skewY` * Perspective: `transformPerspective` `motion` components have enhanced `style` props, allowing you to set individual transforms: <motion.section style\={{ x: -20 }} /> Animating transforms independently provides great flexibility, especially around gestures. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} /> Independent transforms perform great, but Motion's hybrid engine also uniquely offers hardware acceleration by setting `transform` directly. <motion.li initial\={{ transform: "translateX(-100px)" }} animate\={{ transform: "translateX(0px)" }} transition\={{ type: "spring" }} /> **SVG note:** For SVG components, `x` and `y` **attributes** can be set using `attrX` and `attrY`. ### 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 for React can animate the value of CSS variables, and also use CSS variables as animation targets. #### Animating CSS variables Sometimes it's convenient to be able to animate a CSS variable to animate many children: <motion.ul initial\={{ '--rotate': '0deg' }} animate\={{ '--rotate': '360deg' }} transition\={{ duration: 2, repeat: Infinity }} \> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> </motion.ul\> **Note:** Animating the value of a CSS variable **always triggers paint**, therefore it can be more performant to use `MotionValue`s to setup this kind of animation. ### CSS variables as animation targets HTML `motion` components accept animation targets with CSS variables: <motion.li animate\={{ backgroundColor: "var(--action-bg)" }} /> #### SVG line drawing Line drawing animations can be created with many different SVG elements using three special properties: `pathLength`, `pathSpacing` and `pathOffset`. <motion.path initial\={{ pathLength: 0 }} animate\={{ pathLength: 1 }} /> All three are set as a progress value between `0` and `1`, `1` representing the total length of the path. Path animations are compatible with `circle`, `ellipse`, `line`, `path`, `polygon`, `polyline` and `rect` elements. ## Transitions By default, Motion will create appropriate transitions for snappy animations based on the type of value being animated. For instance, physical properties like `x` or `scale` are animated with spring physics, whereas values like `opacity` or `color` are animated with duration-based easing curves. However, you can define your own animations via the `transition` prop. <motion.div animate\={{ x: 100 }} transition\={{ ease: "easeOut", duration: 2 }} /> ## Enter animations When a `motion` component is first created, it'll automatically animate to the values in `animate` if they're different from those initially rendered, which you can either do via CSS or via the `initial` prop. <motion.li initial\={{ opacity: 0, scale: 0 }} animate\={{ opacity: 1, scale: 1 }} /> You can also disable the enter animation entirely by setting `initial={false}`. This will make the element render with the values defined in `animate`. <motion.div initial\={false} animate\={{ y: 100 }} /> ## Exit animations You can also easily animate elements as they exit the DOM. In React, when a component is removed, it's usually removed instantly. Motion provides the `AnimatePresence` component which keeps elements in the DOM while they perform an `exit` animation. <AnimatePresence\> {isVisible && ( <motion.div key\="modal" initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} /> )} </AnimatePresence\> ## Keyframes Values in `animate` can be set as a series of keyframes. This will animate through each value in sequence. <motion.div animate\={{ x: \[0, 100, 0\] }} /> We can use a value's current state as the initial keyframe by setting it to `null`. <motion.div animate\={{ x: \[null, 100, 0\] }} /> This way, if a keyframe animation is interrupting another animation, the transition will feel more natural. By default, each keyframe is spaced naturally throughout the animation. You can override this by setting the `times` option via `transition`. `times` is an array of progress values between `0` and `1`, defining where in the animation each keyframe should be positioned. <motion.circle cx\={500} animate\={{ cx: \[null, 100, 200\], transition: { duration: 3, times: \[0, 0.2, 1\] } }} /> ## Gesture animations Motion for React has shortcut props for animating to/from a target when a gesture starts/ends. <motion.button initial\={{ opacity: 0 }} whileHover\={{ backgroundColor: "rgba(220, 220, 220, 1)" }} whileTap\={{ backgroundColor: "rgba(255, 255, 255, 1)" }} whileInView\={{ opacity: 1 }} /> It supports `hover`, `tap`, `drag`, `focus` and `inView`. ## Variants Setting `animate` as a target is useful for simple, single-element animations. But sometimes we want to orchestrate animations that propagate throughout the DOM. We can do so with variants. Variants are a set of named targets. const variants = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } They're passed to `motion` components via the `variants` prop: <motion.div variants\={variants} /> These variants can now be referred to by a label, wherever you can define an animation target: <motion.div variants\={variants} initial\="hidden" whileInView\="visible" /> You can also define multiple variants via an array: animate\={\["visible", "danger"\]} > _I love using variants alongside React state – just pass your state to_ `_animate_`_, and now you've got a tidy place to define all your animation targets!_ > > const \[status, setStatus\] = useState<"inactive" | "active" | "complete"\>( > "inactive" > ); > > <motion.div > animate\={status} // pass in our React state! > variants\={{ > inactive: { scale: 0.9 color: "var(--gray-500)" }, > active: { scale: 1 color: "var(--blue-500)" }, > complete: { scale: 1 color: "var(--blue-500)" } > }} > \> > <motion.svg > path\={checkmarkPath} > variants\={{ > inactive: { pathLength: 0 }, > active: { pathLength: 0 }, > complete: { pathLength: 1} > }} > /> > </motion.div\> > > ~ Sam Selikoff, Motion for React Recipes ### Propagation This is already useful for reusing and combining animation targets. But it becomes powerful for orchestrating animations throughout trees. Variants will flow down through `motion` components. So in this example when the `ul` enters the viewport, all of its children with a "visible" variant will also animate in: const list = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } const item = { visible: { opacity: 1, x: 0 }, hidden: { opacity: 0, x: -100 }, } return ( <motion.ul initial\="hidden" whileInView\="visible" variants\={list} \> <motion.li variants\={item} /> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) ### Orchestration By default, this children animations will start simultaneously with the parent. But with variants we gain access to new `transition` props like `when`, `delayChildren`, `staggerChildren` and `staggerDirection`. const list = { visible: { opacity: 1, transition: { when: "beforeChildren", staggerChildren: 0.3, // Stagger children by .3 seconds }, }, hidden: { opacity: 0, transition: { when: "afterChildren", }, }, } ### Dynamic variants Each variant can be defined as a function that resolves when a variant is made active. const variants = { hidden: { opacity: 0 }, visible: (index) \=> ({ opacity: 1, transition: { delay: index \* 0.3 } }) } These functions are provided a single argument, which is passed via the `custom` prop: items.map((item, index) \=> <motion.div custom\={index} variants\={variants} />) This way, variants can be resolved differently for each animating element. ## Animation controls Declarative animations are ideal for most UI interactions. But sometimes we need to take manual control over animation playback. The `useAnimate` hook can be used for: * Animating any HTML/SVG element (not just `motion` components). * Complex animation sequences. * Controlling animations with `time`, `speed`, `play()`, `pause()` and other playback controls. function MyComponent() { const \[scope, animate\] = useAnimate() useEffect(() \=> { const controls = animate(\[ \[scope.current, { x: "100%" }\], \["li", { opacity: 1 }\] \]) controls.speed = 0.8 return () \=> controls.stop() }, \[\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ## Animate content By passing a `MotionValue` as the child of a `motion` component, it will render its latest value in the HTML. import { useMotionValue, motion, animate } from "motion/react" function Counter() { const count = useMotionValue(0) useEffect(() \=> { const controls = animate(count, 100, { duration: 5 }) return () \=> controls.stop() }, \[\]) return <motion.pre\>{count}</motion.pre\> } This is more performant than setting React state as the `motion` component will set `innerHTML` directly. Motion for React offers a number of ways to animate your UI. Scaling from extremely simple prop-based animations, to more complex orchestration. ## Basic animations You'll perform almost all animations on a `<motion />` component. This is basically a DOM element with motion superpowers. import { motion } from "motion/react" For basic animations, you can update values on the `animate` prop: <motion.div animate\={{ opacity: 1 }} /> When any value in its animate prop changes, the component will automatically animate to the new target. ## Animatable values Motion can animate any CSS value, even those that can't be animated by browsers, like `mask-image`. It supports: * Numbers: `0`, `100` etc. * Strings containing numbers: `"0vh"`, `"10px"` etc. * Colors: Hex, RGBA, HSLA. * Complex strings containing multiple numbers and/or colors (like `box-shadow`). * `display: "none"/"block"` and `visibility: "hidden"/"visible"`. ### Value type conversion In general, values can only be animated between two of the same type (i.e `"0px"` to `"100px"`). Colors can be freely animated between hex, RGBA and HSLA types. Additionally, `x`, `y`, `width`, `height`, `top`, `left`, `right` and `bottom` can animate between different value types. <motion.div initial\={{ x: "100%" }} animate\={{ x: "calc(100vw - 50%)" }} /> It's also possible to animate `width` and `height` in to/out of `"auto"`. <motion.div initial\={{ height: 0 }} animate\={{ height: "auto" }} /> **Note:** If additionally animating `display` in to/out of `"none"`, replace this with `visibility` `"hidden"` as elements with `display: none` can't be measured. ### Transforms Unlike CSS, Motion can animate every transform axis independently: * Translate: `x`, `y`, `z` * Scale: `scale`, `scaleX`, `scaleY` * Rotate: `rotate`, `rotateX`, `rotateY`, `rotateZ` * Skew: `skew`, `skewX`, `skewY` * Perspective: `transformPerspective` `motion` components have enhanced `style` props, allowing you to set individual transforms: <motion.section style\={{ x: -20 }} /> Animating transforms independently provides great flexibility, especially around gestures. <motion.button whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} /> Independent transforms perform great, but Motion's hybrid engine also uniquely offers hardware acceleration by setting `transform` directly. <motion.li initial\={{ transform: "translateX(-100px)" }} animate\={{ transform: "translateX(0px)" }} transition\={{ type: "spring" }} /> **SVG note:** For SVG components, `x` and `y` **attributes** can be set using `attrX` and `attrY`. ### 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 for React can animate the value of CSS variables, and also use CSS variables as animation targets. #### Animating CSS variables Sometimes it's convenient to be able to animate a CSS variable to animate many children: <motion.ul initial\={{ '--rotate': '0deg' }} animate\={{ '--rotate': '360deg' }} transition\={{ duration: 2, repeat: Infinity }} \> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> <li style\={{ transform: 'rotate(var(--rotate))' }} /> </motion.ul\> **Note:** Animating the value of a CSS variable **always triggers paint**, therefore it can be more performant to use `MotionValue`s to setup this kind of animation. ### CSS variables as animation targets HTML `motion` components accept animation targets with CSS variables: <motion.li animate\={{ backgroundColor: "var(--action-bg)" }} /> #### SVG line drawing Line drawing animations can be created with many different SVG elements using three special properties: `pathLength`, `pathSpacing` and `pathOffset`. <motion.path initial\={{ pathLength: 0 }} animate\={{ pathLength: 1 }} /> All three are set as a progress value between `0` and `1`, `1` representing the total length of the path. Path animations are compatible with `circle`, `ellipse`, `line`, `path`, `polygon`, `polyline` and `rect` elements. ## Transitions By default, Motion will create appropriate transitions for snappy animations based on the type of value being animated. For instance, physical properties like `x` or `scale` are animated with spring physics, whereas values like `opacity` or `color` are animated with duration-based easing curves. However, you can define your own animations via the `transition` prop. <motion.div animate\={{ x: 100 }} transition\={{ ease: "easeOut", duration: 2 }} /> ## Enter animations When a `motion` component is first created, it'll automatically animate to the values in `animate` if they're different from those initially rendered, which you can either do via CSS or via the `initial` prop. <motion.li initial\={{ opacity: 0, scale: 0 }} animate\={{ opacity: 1, scale: 1 }} /> You can also disable the enter animation entirely by setting `initial={false}`. This will make the element render with the values defined in `animate`. <motion.div initial\={false} animate\={{ y: 100 }} /> ## Exit animations You can also easily animate elements as they exit the DOM. In React, when a component is removed, it's usually removed instantly. Motion provides the `AnimatePresence` component which keeps elements in the DOM while they perform an `exit` animation. <AnimatePresence\> {isVisible && ( <motion.div key\="modal" initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} /> )} </AnimatePresence\> ## Keyframes Values in `animate` can be set as a series of keyframes. This will animate through each value in sequence. <motion.div animate\={{ x: \[0, 100, 0\] }} /> We can use a value's current state as the initial keyframe by setting it to `null`. <motion.div animate\={{ x: \[null, 100, 0\] }} /> This way, if a keyframe animation is interrupting another animation, the transition will feel more natural. By default, each keyframe is spaced naturally throughout the animation. You can override this by setting the `times` option via `transition`. `times` is an array of progress values between `0` and `1`, defining where in the animation each keyframe should be positioned. <motion.circle cx\={500} animate\={{ cx: \[null, 100, 200\], transition: { duration: 3, times: \[0, 0.2, 1\] } }} /> ## Gesture animations Motion for React has shortcut props for animating to/from a target when a gesture starts/ends. <motion.button initial\={{ opacity: 0 }} whileHover\={{ backgroundColor: "rgba(220, 220, 220, 1)" }} whileTap\={{ backgroundColor: "rgba(255, 255, 255, 1)" }} whileInView\={{ opacity: 1 }} /> It supports `hover`, `tap`, `drag`, `focus` and `inView`. ## Variants Setting `animate` as a target is useful for simple, single-element animations. But sometimes we want to orchestrate animations that propagate throughout the DOM. We can do so with variants. Variants are a set of named targets. const variants = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } They're passed to `motion` components via the `variants` prop: <motion.div variants\={variants} /> These variants can now be referred to by a label, wherever you can define an animation target: <motion.div variants\={variants} initial\="hidden" whileInView\="visible" /> You can also define multiple variants via an array: animate\={\["visible", "danger"\]} > _I love using variants alongside React state – just pass your state to_ `_animate_`_, and now you've got a tidy place to define all your animation targets!_ > > const \[status, setStatus\] = useState<"inactive" | "active" | "complete"\>( > "inactive" > ); > > <motion.div > animate\={status} // pass in our React state! > variants\={{ > inactive: { scale: 0.9 color: "var(--gray-500)" }, > active: { scale: 1 color: "var(--blue-500)" }, > complete: { scale: 1 color: "var(--blue-500)" } > }} > \> > <motion.svg > path\={checkmarkPath} > variants\={{ > inactive: { pathLength: 0 }, > active: { pathLength: 0 }, > complete: { pathLength: 1} > }} > /> > </motion.div\> > > ~ Sam Selikoff, Motion for React Recipes ### Propagation This is already useful for reusing and combining animation targets. But it becomes powerful for orchestrating animations throughout trees. Variants will flow down through `motion` components. So in this example when the `ul` enters the viewport, all of its children with a "visible" variant will also animate in: const list = { visible: { opacity: 1 }, hidden: { opacity: 0 }, } const item = { visible: { opacity: 1, x: 0 }, hidden: { opacity: 0, x: -100 }, } return ( <motion.ul initial\="hidden" whileInView\="visible" variants\={list} \> <motion.li variants\={item} /> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) ### Orchestration By default, this children animations will start simultaneously with the parent. But with variants we gain access to new `transition` props like `when`, `delayChildren`, `staggerChildren` and `staggerDirection`. const list = { visible: { opacity: 1, transition: { when: "beforeChildren", staggerChildren: 0.3, // Stagger children by .3 seconds }, }, hidden: { opacity: 0, transition: { when: "afterChildren", }, }, } ### Dynamic variants Each variant can be defined as a function that resolves when a variant is made active. const variants = { hidden: { opacity: 0 }, visible: (index) \=> ({ opacity: 1, transition: { delay: index \* 0.3 } }) } These functions are provided a single argument, which is passed via the `custom` prop: items.map((item, index) \=> <motion.div custom\={index} variants\={variants} />) This way, variants can be resolved differently for each animating element. ## Animation controls Declarative animations are ideal for most UI interactions. But sometimes we need to take manual control over animation playback. The `useAnimate` hook can be used for: * Animating any HTML/SVG element (not just `motion` components). * Complex animation sequences. * Controlling animations with `time`, `speed`, `play()`, `pause()` and other playback controls. function MyComponent() { const \[scope, animate\] = useAnimate() useEffect(() \=> { const controls = animate(\[ \[scope.current, { x: "100%" }\], \["li", { opacity: 1 }\] \]) controls.speed = 0.8 return () \=> controls.stop() }, \[\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ## Animate content By passing a `MotionValue` as the child of a `motion` component, it will render its latest value in the HTML. import { useMotionValue, motion, animate } from "motion/react" function Counter() { const count = useMotionValue(0) useEffect(() \=> { const controls = animate(count, 100, { duration: 5 }) return () \=> controls.stop() }, \[\]) return <motion.pre\>{count}</motion.pre\> } This is more performant than setting React state as the `motion` component will set `innerHTML` directly. --- ## Page: https://motion.dev/docs/react-gestures # Gestures Motion extends React's basic set of event listeners with a simple yet powerful set of UI gestures. The `motion` component currently has support for **hover**, **tap**, **pan**, **drag** and **inView**. Each gesture has both a set of event listeners and a `while-` animation prop. ## Animation props `motion` components provide multiple gesture animation props: `whileHover`, `whileTap`, `whileFocus`, `whileDrag` and `whileInView`. These can define animation targets to temporarily animate to while a gesture is active. <motion.button whileHover\={{ scale: 1.2, transition: { duration: 1 }, }} whileTap\={{ scale: 0.9 }} /> All props can be set either as a target of values to animate to, or the name of any variants defined via the `variants` prop. Variants will flow down through children as normal. <motion.button whileTap\="tap" whileHover\="hover" variants\={buttonVariants} \> <svg\> <motion.path variants\={iconVariants} /> </svg\> </motion.button\> ## Gestures ### Hover The hover gesture detects when a pointer hovers over or leaves a component. It differs from `onMouseEnter` and `onMouseLeave` in that hover is guaranteed to only fire as a result of actual mouse events (as opposed to browser-generated mice events emulated from touch input). <motion.a whileHover\={{ scale: 1.2 }} onHoverStart\={event \=> {}} onHoverEnd\={event \=> {}} /> ### Tap The tap gesture detects when the **primary pointer** (like a left click or first touch point) presses down and releases on the same component. <motion.button whileTap\={{ scale: 0.9, rotate: 3 }} /> It will fire a `tap` event when the tap or click ends on the same component it started on, and a `tapCancel` event if the tap or click ends outside the component. If the tappable component is a child of a draggable component, it'll automatically cancel the tap gesture if the pointer moves further than 3 pixels during the gesture. #### Accessibility Elements with tap events are keyboard-accessible. Any element with a tap prop will be able to receive focus and `Enter` can be used to trigger tap events on focused elements. * Pressing `Enter` down will trigger `onTapStart` and `whileTap` * Releasing `Enter` will trigger `onTap` * If the element loses focus before `Enter` is released, `onTapCancel` will fire. ### Pan The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels. The pan gesture is ended when the pointer is released. <motion.div onPan\={(e, pointInfo) \=> {}} /> Pan doesn't currently have an associated `while-` prop. **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. ### Drag The drag gesture applies pointer movement to the x and/or y axis of the component. <motion.div drag whileDrag\={{ scale: 1.2, backgroundColor: "#f00" }} /> By default, when the drag ends the element will perform an inertia animation with the ending velocity. This can be disabled by setting `dragMomentum` to `false`, or changed via the `dragTransition` prop. #### Constraints It's also possible to set `dragConstraints`, either as an object with `top`, `left`, `right`, and `bottom` values, measured in pixels. <motion.div drag\="x" dragConstraints\={{ left: 0, right: 300 }} /> Or, it can accept a `ref` to another component created with React's `useRef` hook. This `ref` should be passed both to the draggable component's `dragConstraints` prop, and the `ref` of the component you want to use as constraints. const MyComponent = () \=> { const constraintsRef = useRef(null) return ( <motion.div ref\={constraintsRef}\> <motion.div drag dragConstraints\={constraintsRef} /> </motion.div\> ) } By default, dragging the element outside the constraints will tug with some elasticity. This can be changed by setting `dragElastic` to a value between `0` and `1`, where `0` equals no motion and `1` equals full motion outside the constraints. #### Direction locking It's possible to lock an element to the first axis it's dragged on by setting `dragDirectionLock`. <motion.div drag dragDirectionLock onDirectionLock\={callback} /> Each time the drag gesture starts, the direction of pointer travel will be detected and the element will be draggable only on this axis. ### Focus The focus gesture detects when a component gains or loses focus by the same rules as the CSS :focus-visible selector. Typically, this is when an `input` receives focus by any means, and when other elements receive focus by accessible means (like via keyboard navigation). <motion.a whileFocus\={{ scale: 1.2 }} href\="#" /> ## Event propagation Children can stop pointer events propagating to parent `motion` components using the `Capture` React props. For instance, a child can stop drag and tap gestures and their related `while` animations from firing on parents by passing `e.stopPropagation()` to `onPointerDownCapture`. <motion.div whileTap\={{ scale: 2 }}\> <button onPointerDownCapture\={e \=> e.stopPropagation()} /> </motion.div\> ## Note: SVG filters Gestures aren't recognised on SVG `filter` components, as these elements don't have a physical presence and therefore don't receive events. You can instead add `while-` props and event handlers to a parent and use variants to animate these elements. const MyComponent = () \=> { return ( <motion.svg whileHover\="hover"\> <filter id\="blur"\> <motion.feGaussianBlur stdDeviation\={0} variants\={{ hover: { stdDeviation: 2 } }} /> </filter\> </motion.svg\> ) } Motion extends React's basic set of event listeners with a simple yet powerful set of UI gestures. The `motion` component currently has support for **hover**, **tap**, **pan**, **drag** and **inView**. Each gesture has both a set of event listeners and a `while-` animation prop. ## Animation props `motion` components provide multiple gesture animation props: `whileHover`, `whileTap`, `whileFocus`, `whileDrag` and `whileInView`. These can define animation targets to temporarily animate to while a gesture is active. <motion.button whileHover\={{ scale: 1.2, transition: { duration: 1 }, }} whileTap\={{ scale: 0.9 }} /> All props can be set either as a target of values to animate to, or the name of any variants defined via the `variants` prop. Variants will flow down through children as normal. <motion.button whileTap\="tap" whileHover\="hover" variants\={buttonVariants} \> <svg\> <motion.path variants\={iconVariants} /> </svg\> </motion.button\> ## Gestures ### Hover The hover gesture detects when a pointer hovers over or leaves a component. It differs from `onMouseEnter` and `onMouseLeave` in that hover is guaranteed to only fire as a result of actual mouse events (as opposed to browser-generated mice events emulated from touch input). <motion.a whileHover\={{ scale: 1.2 }} onHoverStart\={event \=> {}} onHoverEnd\={event \=> {}} /> ### Tap The tap gesture detects when the **primary pointer** (like a left click or first touch point) presses down and releases on the same component. <motion.button whileTap\={{ scale: 0.9, rotate: 3 }} /> It will fire a `tap` event when the tap or click ends on the same component it started on, and a `tapCancel` event if the tap or click ends outside the component. If the tappable component is a child of a draggable component, it'll automatically cancel the tap gesture if the pointer moves further than 3 pixels during the gesture. #### Accessibility Elements with tap events are keyboard-accessible. Any element with a tap prop will be able to receive focus and `Enter` can be used to trigger tap events on focused elements. * Pressing `Enter` down will trigger `onTapStart` and `whileTap` * Releasing `Enter` will trigger `onTap` * If the element loses focus before `Enter` is released, `onTapCancel` will fire. ### Pan The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels. The pan gesture is ended when the pointer is released. <motion.div onPan\={(e, pointInfo) \=> {}} /> Pan doesn't currently have an associated `while-` prop. **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. ### Drag The drag gesture applies pointer movement to the x and/or y axis of the component. <motion.div drag whileDrag\={{ scale: 1.2, backgroundColor: "#f00" }} /> By default, when the drag ends the element will perform an inertia animation with the ending velocity. This can be disabled by setting `dragMomentum` to `false`, or changed via the `dragTransition` prop. #### Constraints It's also possible to set `dragConstraints`, either as an object with `top`, `left`, `right`, and `bottom` values, measured in pixels. <motion.div drag\="x" dragConstraints\={{ left: 0, right: 300 }} /> Or, it can accept a `ref` to another component created with React's `useRef` hook. This `ref` should be passed both to the draggable component's `dragConstraints` prop, and the `ref` of the component you want to use as constraints. const MyComponent = () \=> { const constraintsRef = useRef(null) return ( <motion.div ref\={constraintsRef}\> <motion.div drag dragConstraints\={constraintsRef} /> </motion.div\> ) } By default, dragging the element outside the constraints will tug with some elasticity. This can be changed by setting `dragElastic` to a value between `0` and `1`, where `0` equals no motion and `1` equals full motion outside the constraints. #### Direction locking It's possible to lock an element to the first axis it's dragged on by setting `dragDirectionLock`. <motion.div drag dragDirectionLock onDirectionLock\={callback} /> Each time the drag gesture starts, the direction of pointer travel will be detected and the element will be draggable only on this axis. ### Focus The focus gesture detects when a component gains or loses focus by the same rules as the CSS :focus-visible selector. Typically, this is when an `input` receives focus by any means, and when other elements receive focus by accessible means (like via keyboard navigation). <motion.a whileFocus\={{ scale: 1.2 }} href\="#" /> ## Event propagation Children can stop pointer events propagating to parent `motion` components using the `Capture` React props. For instance, a child can stop drag and tap gestures and their related `while` animations from firing on parents by passing `e.stopPropagation()` to `onPointerDownCapture`. <motion.div whileTap\={{ scale: 2 }}\> <button onPointerDownCapture\={e \=> e.stopPropagation()} /> </motion.div\> ## Note: SVG filters Gestures aren't recognised on SVG `filter` components, as these elements don't have a physical presence and therefore don't receive events. You can instead add `while-` props and event handlers to a parent and use variants to animate these elements. const MyComponent = () \=> { return ( <motion.svg whileHover\="hover"\> <filter id\="blur"\> <motion.feGaussianBlur stdDeviation\={0} variants\={{ hover: { stdDeviation: 2 } }} /> </filter\> </motion.svg\> ) } Motion extends React's basic set of event listeners with a simple yet powerful set of UI gestures. The `motion` component currently has support for **hover**, **tap**, **pan**, **drag** and **inView**. Each gesture has both a set of event listeners and a `while-` animation prop. ## Animation props `motion` components provide multiple gesture animation props: `whileHover`, `whileTap`, `whileFocus`, `whileDrag` and `whileInView`. These can define animation targets to temporarily animate to while a gesture is active. <motion.button whileHover\={{ scale: 1.2, transition: { duration: 1 }, }} whileTap\={{ scale: 0.9 }} /> All props can be set either as a target of values to animate to, or the name of any variants defined via the `variants` prop. Variants will flow down through children as normal. <motion.button whileTap\="tap" whileHover\="hover" variants\={buttonVariants} \> <svg\> <motion.path variants\={iconVariants} /> </svg\> </motion.button\> ## Gestures ### Hover The hover gesture detects when a pointer hovers over or leaves a component. It differs from `onMouseEnter` and `onMouseLeave` in that hover is guaranteed to only fire as a result of actual mouse events (as opposed to browser-generated mice events emulated from touch input). <motion.a whileHover\={{ scale: 1.2 }} onHoverStart\={event \=> {}} onHoverEnd\={event \=> {}} /> ### Tap The tap gesture detects when the **primary pointer** (like a left click or first touch point) presses down and releases on the same component. <motion.button whileTap\={{ scale: 0.9, rotate: 3 }} /> It will fire a `tap` event when the tap or click ends on the same component it started on, and a `tapCancel` event if the tap or click ends outside the component. If the tappable component is a child of a draggable component, it'll automatically cancel the tap gesture if the pointer moves further than 3 pixels during the gesture. #### Accessibility Elements with tap events are keyboard-accessible. Any element with a tap prop will be able to receive focus and `Enter` can be used to trigger tap events on focused elements. * Pressing `Enter` down will trigger `onTapStart` and `whileTap` * Releasing `Enter` will trigger `onTap` * If the element loses focus before `Enter` is released, `onTapCancel` will fire. ### Pan The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels. The pan gesture is ended when the pointer is released. <motion.div onPan\={(e, pointInfo) \=> {}} /> Pan doesn't currently have an associated `while-` prop. **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. ### Drag The drag gesture applies pointer movement to the x and/or y axis of the component. <motion.div drag whileDrag\={{ scale: 1.2, backgroundColor: "#f00" }} /> By default, when the drag ends the element will perform an inertia animation with the ending velocity. This can be disabled by setting `dragMomentum` to `false`, or changed via the `dragTransition` prop. #### Constraints It's also possible to set `dragConstraints`, either as an object with `top`, `left`, `right`, and `bottom` values, measured in pixels. <motion.div drag\="x" dragConstraints\={{ left: 0, right: 300 }} /> Or, it can accept a `ref` to another component created with React's `useRef` hook. This `ref` should be passed both to the draggable component's `dragConstraints` prop, and the `ref` of the component you want to use as constraints. const MyComponent = () \=> { const constraintsRef = useRef(null) return ( <motion.div ref\={constraintsRef}\> <motion.div drag dragConstraints\={constraintsRef} /> </motion.div\> ) } By default, dragging the element outside the constraints will tug with some elasticity. This can be changed by setting `dragElastic` to a value between `0` and `1`, where `0` equals no motion and `1` equals full motion outside the constraints. #### Direction locking It's possible to lock an element to the first axis it's dragged on by setting `dragDirectionLock`. <motion.div drag dragDirectionLock onDirectionLock\={callback} /> Each time the drag gesture starts, the direction of pointer travel will be detected and the element will be draggable only on this axis. ### Focus The focus gesture detects when a component gains or loses focus by the same rules as the CSS :focus-visible selector. Typically, this is when an `input` receives focus by any means, and when other elements receive focus by accessible means (like via keyboard navigation). <motion.a whileFocus\={{ scale: 1.2 }} href\="#" /> ## Event propagation Children can stop pointer events propagating to parent `motion` components using the `Capture` React props. For instance, a child can stop drag and tap gestures and their related `while` animations from firing on parents by passing `e.stopPropagation()` to `onPointerDownCapture`. <motion.div whileTap\={{ scale: 2 }}\> <button onPointerDownCapture\={e \=> e.stopPropagation()} /> </motion.div\> ## Note: SVG filters Gestures aren't recognised on SVG `filter` components, as these elements don't have a physical presence and therefore don't receive events. You can instead add `while-` props and event handlers to a parent and use variants to animate these elements. const MyComponent = () \=> { return ( <motion.svg whileHover\="hover"\> <filter id\="blur"\> <motion.feGaussianBlur stdDeviation\={0} variants\={{ hover: { stdDeviation: 2 } }} /> </filter\> </motion.svg\> ) } --- ## Page: https://motion.dev/docs/react-layout-animations # Layout animations Motion's industry-leading layout animations makes it easy to animate between any two layouts, even between different elements. It's as simple as a `layout` prop. <motion.div layout /> > _One of the coolest things about layout animations is that they effectively make **any** CSS property transitionable. You can’t apply a CSS transition to_ `_flex-direction_` _or_ `_grid-template-columns_`_, but with layout animations, you can. Plus, the animation uses super-efficient transforms, so the motion will be smooth! > > _~ Josh W. Comeau, The Joy of React This little prop can animate previously unanimatable CSS values, like switching `justify-content` between `flex-start` and `flex-end`. <motion.div layout style\={{ justifyContent: isOn ? "flex-start" : "flex-end" }} /> Or by using the `layoutId` prop, it's possible to match two elements and animate between them for some truly advanced animations. <motion.li layoutId\="item" /> It can handle anything from microinteractions to full page transitions. ## Usage Any layout change that happens as a result of a React re-render can be animated. <motion.div layout style\={{ width: isOpen ? "80vw" : 0 }} /> Note that CSS changes should happen immediately via `style`, not `animate`, as `layout` will take care of the animation. Layout changes can be anything, changing `width`/`height`, number of grid columns, reordering a list, or adding/removing new items: ### Shared layout animations When a new component is added that has a `layoutId` prop that matches an existing component, it will automatically animate out from the old component. isSelected && <motion.div layoutId\="underline" /> If the old component is still mounted when the new component enters, they will automatically crossfade from the old to the new. When removing an element to animate back to its origin layout, `AnimatePresence` can be used to keep it in the DOM until its exit animation has finished. <AnimatePresence\> {isOpen && <motion.div layoutId\="modal" />} </AnimatePresence\> ### Setting a transition Layout animations can be customised using the `transition` prop. <motion.div layout transition\={{ duration: 0.3 }} /> If you want to set a transition specifically for **only** the layout animation, you can specify a specific `layout` transition. <motion.div layout animate\={{ opacity: 0.5 }} transition\={{ default: { ease: "linear" }, layout: { duration: 0.3 } }} /> When performing a shared layout animation, the transition defined for element we're animating **to** will be used. <\> <motion.button layoutId\="modal" onClick\={() \=> setIsOpen(true)} // This transition will be used when the modal closes transition\={{ type: "spring" }} \> Open </motion.button\> <AnimatePresence\> {isOn && ( <motion.dialog layoutId\="modal" // This transition will be used when the modal opens transition\={{ duration: 0.3 }} /> )} </AnimatePresence\> </\> ### Animating within scrollable element To correctly animate layout within scrollable elements, we need to provide them the `layoutScroll` prop. <motion.div layoutScroll style\={{ overflow: "scroll" }} /> This lets Motion account for the element's scroll offset when measuring children. ### Animating within fixed containers To correctly animate layout within fixed elements, we need to provide them the `layoutRoot` prop. <motion.div layoutRoot style\={{ position: "fixed" }} /> This lets Motion account for the page's scroll offset when measuring children. ### Group layout animations Layout animations are triggered when a component re-renders and its layout has changed. function Accordion() { const \[isOpen, setOpen\] = useState(false) return ( <motion.div layout style\={{ height: isOpen ? "100px" : "500px" }} onClick\={() \=> setOpen(!isOpen)} /> ) } But what happens when we have two or more components that don't re-render at the same time, but **do** affect each other's layout? function List() { return ( <\> <Accordion /> <Accordion /> </\> ) } When one re-renders, for performance reasons the other won't be able to detect changes to its layout. We can synchronise layout changes across multiple components by wrapping them in the `LayoutGroup component`. import { LayoutGroup } from "motion/react" function List() { return ( <LayoutGroup\> <Accordion /> <Accordion /> </LayoutGroup\> ) } When layout changes are detected in any grouped `motion` component, layout animations will trigger across all of them. ### Scale correction All layout animations are performed using the `transform` style, resulting in smooth framerates. Animating layout using transforms can sometimes visually distort children. To correct this distortion, the first child elements of the element can also be given `layout` property. Open this sandbox and try removing `layout` from the pink dot to see the difference this will make: Transforms can also distort `boxShadow` and `borderRadius`. The `motion` component will automatically correct this distortion on both props, as long as they're set as motion values. If you're not animating these values, the easiest way to do this is to set them via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ## Troubleshooting ### The component isn't animating Ensure the component is **not** set to `display: inline`, as browsers don't apply `transform` to these elements. Ensure the component is re-rendering when you expect the layout animation to start. ### SVG layout animations are broken SVG components aren't currently supported with layout animations. SVGs don't have layout systems so it's recommended to directly animate their attributes like `cx` etc. ### The content stretches undesirably This is a natural side-effect of animating `width` and `height` with `scale`. Often, this can be fixed by providing these elements a `layout` animation and they'll be scale-corrected. <motion.section layout\> <motion.img layout /> </motion.section\> Some elements, like images or text that are changing between different aspect ratios, might be better animated with `layout="position"`. ### Border radius or box shadows are behaving strangely Animating `scale` is performant but can distort some styles like `border-radius` and `box-shadow`. Motion automatically corrects for scale distortion on these properties, but they must be set on the element via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ### Border looks stretched during animation Elements with a `border` may look stretched during the animation. This is for two reasons: 1. Because changing `border` triggers layout recalculations, it defeats the performance benefits of animating via `transform`. You might as well animate `width` and `height` classically. 2. `border` can't render smaller than `1px`, which limits the degree of scale correction that Motion can perform on this style. A work around is to replace `border` with a parent element with padding that acts as a `border`. <motion.div layout style\={{ borderRadius: 10, padding: 5 }}\> <motion.div layout style\={{ borderRadius: 5 }} /> </motion.div\> ## Technical reading Interested in the technical details behind layout animations? Nanda does an incredible job of explaining the challenges of animating layout with transforms using interactive examples. Matt, creator of Motion, did a talk at Vercel conference about the implementation details that is largely up to date. ## Differences with the View Transitions API More browsers are starting to support the View Transitions API, which is similar to Motion's layout animations. ### Benefits of View Transitions API The main two benefits of View Transitions is that **it's included in browsers** and **features a unique rendering system**. #### Filesize Because the View Transitions API is already included in browsers, it's cheap to implement very simple crossfade animations. However, the CSS complexity can scale quite quickly. Motion's layout animations are around 12kb but from there it's very cheap to change transitions, add springs, mark matching #### Rendering Whereas Motion animates the elements as they exist on the page, View Transitions API does something quite unique in that it takes an image snapshot of the previous page state, and crossfades it with a live view of the new page state. For shared elements, it does the same thing, taking little image snapshots and then crossfading those with a live view of the element's new state. This can be leveraged to create interesting effects like full-screen wipes that aren't really in the scope of layout animations. Framer's Page Effects were built with the View Transitions API and it also extensively uses layout animations. The right tool for the right job. ### Drawbacks to View Transitions API There are quite a few drawbacks to the API vs layout animations: * **Not interruptible**: Interrupting an animation mid-way will snap the animation to the end before starting the next one. This feels very janky. * **Blocks interaction**: The animating elements overlay the "real" page underneath and block pointer events. Makes things feel quite sticky. * **Difficult to manage IDs**: Layout animations allow more than one element with a `layoutId` whereas View Transitions will break if the previous element isn't removed. * **Less performant:** View Transitions take an actual screenshot and animate via `width`/`height` vs layout animation's `transform`. This is measurably less performant when animating many elements. * **Doesn't account for scroll**: If the page scroll changes during a view transition, elements will incorrectly animate this delta. * **No relative animations:** If a nested element has a `delay` it will get "left behind" when its parent animates away, whereas Motion handles this kind of relative animation. * **One animation at a time**: View Transitions animate the whole screen, which means combining it with other animations is difficult and other view animations impossible. All-in-all, each system offers something different and each might be a better fit for your needs. In the future it might be that Motion also offers an API based on View Transitions API. Motion's industry-leading layout animations makes it easy to animate between any two layouts, even between different elements. It's as simple as a `layout` prop. <motion.div layout /> > _One of the coolest things about layout animations is that they effectively make **any** CSS property transitionable. You can’t apply a CSS transition to_ `_flex-direction_` _or_ `_grid-template-columns_`_, but with layout animations, you can. Plus, the animation uses super-efficient transforms, so the motion will be smooth! > > _~ Josh W. Comeau, The Joy of React This little prop can animate previously unanimatable CSS values, like switching `justify-content` between `flex-start` and `flex-end`. <motion.div layout style\={{ justifyContent: isOn ? "flex-start" : "flex-end" }} /> Or by using the `layoutId` prop, it's possible to match two elements and animate between them for some truly advanced animations. <motion.li layoutId\="item" /> It can handle anything from microinteractions to full page transitions. ## Usage Any layout change that happens as a result of a React re-render can be animated. <motion.div layout style\={{ width: isOpen ? "80vw" : 0 }} /> Note that CSS changes should happen immediately via `style`, not `animate`, as `layout` will take care of the animation. Layout changes can be anything, changing `width`/`height`, number of grid columns, reordering a list, or adding/removing new items: ### Shared layout animations When a new component is added that has a `layoutId` prop that matches an existing component, it will automatically animate out from the old component. isSelected && <motion.div layoutId\="underline" /> If the old component is still mounted when the new component enters, they will automatically crossfade from the old to the new. When removing an element to animate back to its origin layout, `AnimatePresence` can be used to keep it in the DOM until its exit animation has finished. <AnimatePresence\> {isOpen && <motion.div layoutId\="modal" />} </AnimatePresence\> ### Setting a transition Layout animations can be customised using the `transition` prop. <motion.div layout transition\={{ duration: 0.3 }} /> If you want to set a transition specifically for **only** the layout animation, you can specify a specific `layout` transition. <motion.div layout animate\={{ opacity: 0.5 }} transition\={{ default: { ease: "linear" }, layout: { duration: 0.3 } }} /> When performing a shared layout animation, the transition defined for element we're animating **to** will be used. <\> <motion.button layoutId\="modal" onClick\={() \=> setIsOpen(true)} // This transition will be used when the modal closes transition\={{ type: "spring" }} \> Open </motion.button\> <AnimatePresence\> {isOn && ( <motion.dialog layoutId\="modal" // This transition will be used when the modal opens transition\={{ duration: 0.3 }} /> )} </AnimatePresence\> </\> ### Animating within scrollable element To correctly animate layout within scrollable elements, we need to provide them the `layoutScroll` prop. <motion.div layoutScroll style\={{ overflow: "scroll" }} /> This lets Motion account for the element's scroll offset when measuring children. ### Animating within fixed containers To correctly animate layout within fixed elements, we need to provide them the `layoutRoot` prop. <motion.div layoutRoot style\={{ position: "fixed" }} /> This lets Motion account for the page's scroll offset when measuring children. ### Group layout animations Layout animations are triggered when a component re-renders and its layout has changed. function Accordion() { const \[isOpen, setOpen\] = useState(false) return ( <motion.div layout style\={{ height: isOpen ? "100px" : "500px" }} onClick\={() \=> setOpen(!isOpen)} /> ) } But what happens when we have two or more components that don't re-render at the same time, but **do** affect each other's layout? function List() { return ( <\> <Accordion /> <Accordion /> </\> ) } When one re-renders, for performance reasons the other won't be able to detect changes to its layout. We can synchronise layout changes across multiple components by wrapping them in the `LayoutGroup component`. import { LayoutGroup } from "motion/react" function List() { return ( <LayoutGroup\> <Accordion /> <Accordion /> </LayoutGroup\> ) } When layout changes are detected in any grouped `motion` component, layout animations will trigger across all of them. ### Scale correction All layout animations are performed using the `transform` style, resulting in smooth framerates. Animating layout using transforms can sometimes visually distort children. To correct this distortion, the first child elements of the element can also be given `layout` property. Open this sandbox and try removing `layout` from the pink dot to see the difference this will make: Transforms can also distort `boxShadow` and `borderRadius`. The `motion` component will automatically correct this distortion on both props, as long as they're set as motion values. If you're not animating these values, the easiest way to do this is to set them via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ## Troubleshooting ### The component isn't animating Ensure the component is **not** set to `display: inline`, as browsers don't apply `transform` to these elements. Ensure the component is re-rendering when you expect the layout animation to start. ### SVG layout animations are broken SVG components aren't currently supported with layout animations. SVGs don't have layout systems so it's recommended to directly animate their attributes like `cx` etc. ### The content stretches undesirably This is a natural side-effect of animating `width` and `height` with `scale`. Often, this can be fixed by providing these elements a `layout` animation and they'll be scale-corrected. <motion.section layout\> <motion.img layout /> </motion.section\> Some elements, like images or text that are changing between different aspect ratios, might be better animated with `layout="position"`. ### Border radius or box shadows are behaving strangely Animating `scale` is performant but can distort some styles like `border-radius` and `box-shadow`. Motion automatically corrects for scale distortion on these properties, but they must be set on the element via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ### Border looks stretched during animation Elements with a `border` may look stretched during the animation. This is for two reasons: 1. Because changing `border` triggers layout recalculations, it defeats the performance benefits of animating via `transform`. You might as well animate `width` and `height` classically. 2. `border` can't render smaller than `1px`, which limits the degree of scale correction that Motion can perform on this style. A work around is to replace `border` with a parent element with padding that acts as a `border`. <motion.div layout style\={{ borderRadius: 10, padding: 5 }}\> <motion.div layout style\={{ borderRadius: 5 }} /> </motion.div\> ## Technical reading Interested in the technical details behind layout animations? Nanda does an incredible job of explaining the challenges of animating layout with transforms using interactive examples. Matt, creator of Motion, did a talk at Vercel conference about the implementation details that is largely up to date. ## Differences with the View Transitions API More browsers are starting to support the View Transitions API, which is similar to Motion's layout animations. ### Benefits of View Transitions API The main two benefits of View Transitions is that **it's included in browsers** and **features a unique rendering system**. #### Filesize Because the View Transitions API is already included in browsers, it's cheap to implement very simple crossfade animations. However, the CSS complexity can scale quite quickly. Motion's layout animations are around 12kb but from there it's very cheap to change transitions, add springs, mark matching #### Rendering Whereas Motion animates the elements as they exist on the page, View Transitions API does something quite unique in that it takes an image snapshot of the previous page state, and crossfades it with a live view of the new page state. For shared elements, it does the same thing, taking little image snapshots and then crossfading those with a live view of the element's new state. This can be leveraged to create interesting effects like full-screen wipes that aren't really in the scope of layout animations. Framer's Page Effects were built with the View Transitions API and it also extensively uses layout animations. The right tool for the right job. ### Drawbacks to View Transitions API There are quite a few drawbacks to the API vs layout animations: * **Not interruptible**: Interrupting an animation mid-way will snap the animation to the end before starting the next one. This feels very janky. * **Blocks interaction**: The animating elements overlay the "real" page underneath and block pointer events. Makes things feel quite sticky. * **Difficult to manage IDs**: Layout animations allow more than one element with a `layoutId` whereas View Transitions will break if the previous element isn't removed. * **Less performant:** View Transitions take an actual screenshot and animate via `width`/`height` vs layout animation's `transform`. This is measurably less performant when animating many elements. * **Doesn't account for scroll**: If the page scroll changes during a view transition, elements will incorrectly animate this delta. * **No relative animations:** If a nested element has a `delay` it will get "left behind" when its parent animates away, whereas Motion handles this kind of relative animation. * **One animation at a time**: View Transitions animate the whole screen, which means combining it with other animations is difficult and other view animations impossible. All-in-all, each system offers something different and each might be a better fit for your needs. In the future it might be that Motion also offers an API based on View Transitions API. Motion's industry-leading layout animations makes it easy to animate between any two layouts, even between different elements. It's as simple as a `layout` prop. <motion.div layout /> > _One of the coolest things about layout animations is that they effectively make **any** CSS property transitionable. You can’t apply a CSS transition to_ `_flex-direction_` _or_ `_grid-template-columns_`_, but with layout animations, you can. Plus, the animation uses super-efficient transforms, so the motion will be smooth! > > _~ Josh W. Comeau, The Joy of React This little prop can animate previously unanimatable CSS values, like switching `justify-content` between `flex-start` and `flex-end`. <motion.div layout style\={{ justifyContent: isOn ? "flex-start" : "flex-end" }} /> Or by using the `layoutId` prop, it's possible to match two elements and animate between them for some truly advanced animations. <motion.li layoutId\="item" /> It can handle anything from microinteractions to full page transitions. ## Usage Any layout change that happens as a result of a React re-render can be animated. <motion.div layout style\={{ width: isOpen ? "80vw" : 0 }} /> Note that CSS changes should happen immediately via `style`, not `animate`, as `layout` will take care of the animation. Layout changes can be anything, changing `width`/`height`, number of grid columns, reordering a list, or adding/removing new items: ### Shared layout animations When a new component is added that has a `layoutId` prop that matches an existing component, it will automatically animate out from the old component. isSelected && <motion.div layoutId\="underline" /> If the old component is still mounted when the new component enters, they will automatically crossfade from the old to the new. When removing an element to animate back to its origin layout, `AnimatePresence` can be used to keep it in the DOM until its exit animation has finished. <AnimatePresence\> {isOpen && <motion.div layoutId\="modal" />} </AnimatePresence\> ### Setting a transition Layout animations can be customised using the `transition` prop. <motion.div layout transition\={{ duration: 0.3 }} /> If you want to set a transition specifically for **only** the layout animation, you can specify a specific `layout` transition. <motion.div layout animate\={{ opacity: 0.5 }} transition\={{ default: { ease: "linear" }, layout: { duration: 0.3 } }} /> When performing a shared layout animation, the transition defined for element we're animating **to** will be used. <\> <motion.button layoutId\="modal" onClick\={() \=> setIsOpen(true)} // This transition will be used when the modal closes transition\={{ type: "spring" }} \> Open </motion.button\> <AnimatePresence\> {isOn && ( <motion.dialog layoutId\="modal" // This transition will be used when the modal opens transition\={{ duration: 0.3 }} /> )} </AnimatePresence\> </\> ### Animating within scrollable element To correctly animate layout within scrollable elements, we need to provide them the `layoutScroll` prop. <motion.div layoutScroll style\={{ overflow: "scroll" }} /> This lets Motion account for the element's scroll offset when measuring children. ### Animating within fixed containers To correctly animate layout within fixed elements, we need to provide them the `layoutRoot` prop. <motion.div layoutRoot style\={{ position: "fixed" }} /> This lets Motion account for the page's scroll offset when measuring children. ### Group layout animations Layout animations are triggered when a component re-renders and its layout has changed. function Accordion() { const \[isOpen, setOpen\] = useState(false) return ( <motion.div layout style\={{ height: isOpen ? "100px" : "500px" }} onClick\={() \=> setOpen(!isOpen)} /> ) } But what happens when we have two or more components that don't re-render at the same time, but **do** affect each other's layout? function List() { return ( <\> <Accordion /> <Accordion /> </\> ) } When one re-renders, for performance reasons the other won't be able to detect changes to its layout. We can synchronise layout changes across multiple components by wrapping them in the `LayoutGroup component`. import { LayoutGroup } from "motion/react" function List() { return ( <LayoutGroup\> <Accordion /> <Accordion /> </LayoutGroup\> ) } When layout changes are detected in any grouped `motion` component, layout animations will trigger across all of them. ### Scale correction All layout animations are performed using the `transform` style, resulting in smooth framerates. Animating layout using transforms can sometimes visually distort children. To correct this distortion, the first child elements of the element can also be given `layout` property. Open this sandbox and try removing `layout` from the pink dot to see the difference this will make: Transforms can also distort `boxShadow` and `borderRadius`. The `motion` component will automatically correct this distortion on both props, as long as they're set as motion values. If you're not animating these values, the easiest way to do this is to set them via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ## Troubleshooting ### The component isn't animating Ensure the component is **not** set to `display: inline`, as browsers don't apply `transform` to these elements. Ensure the component is re-rendering when you expect the layout animation to start. ### SVG layout animations are broken SVG components aren't currently supported with layout animations. SVGs don't have layout systems so it's recommended to directly animate their attributes like `cx` etc. ### The content stretches undesirably This is a natural side-effect of animating `width` and `height` with `scale`. Often, this can be fixed by providing these elements a `layout` animation and they'll be scale-corrected. <motion.section layout\> <motion.img layout /> </motion.section\> Some elements, like images or text that are changing between different aspect ratios, might be better animated with `layout="position"`. ### Border radius or box shadows are behaving strangely Animating `scale` is performant but can distort some styles like `border-radius` and `box-shadow`. Motion automatically corrects for scale distortion on these properties, but they must be set on the element via `style`. <motion.div layout style\={{ borderRadius: 20 }} /> ### Border looks stretched during animation Elements with a `border` may look stretched during the animation. This is for two reasons: 1. Because changing `border` triggers layout recalculations, it defeats the performance benefits of animating via `transform`. You might as well animate `width` and `height` classically. 2. `border` can't render smaller than `1px`, which limits the degree of scale correction that Motion can perform on this style. A work around is to replace `border` with a parent element with padding that acts as a `border`. <motion.div layout style\={{ borderRadius: 10, padding: 5 }}\> <motion.div layout style\={{ borderRadius: 5 }} /> </motion.div\> ## Technical reading Interested in the technical details behind layout animations? Nanda does an incredible job of explaining the challenges of animating layout with transforms using interactive examples. Matt, creator of Motion, did a talk at Vercel conference about the implementation details that is largely up to date. ## Differences with the View Transitions API More browsers are starting to support the View Transitions API, which is similar to Motion's layout animations. ### Benefits of View Transitions API The main two benefits of View Transitions is that **it's included in browsers** and **features a unique rendering system**. #### Filesize Because the View Transitions API is already included in browsers, it's cheap to implement very simple crossfade animations. However, the CSS complexity can scale quite quickly. Motion's layout animations are around 12kb but from there it's very cheap to change transitions, add springs, mark matching #### Rendering Whereas Motion animates the elements as they exist on the page, View Transitions API does something quite unique in that it takes an image snapshot of the previous page state, and crossfades it with a live view of the new page state. For shared elements, it does the same thing, taking little image snapshots and then crossfading those with a live view of the element's new state. This can be leveraged to create interesting effects like full-screen wipes that aren't really in the scope of layout animations. Framer's Page Effects were built with the View Transitions API and it also extensively uses layout animations. The right tool for the right job. ### Drawbacks to View Transitions API There are quite a few drawbacks to the API vs layout animations: * **Not interruptible**: Interrupting an animation mid-way will snap the animation to the end before starting the next one. This feels very janky. * **Blocks interaction**: The animating elements overlay the "real" page underneath and block pointer events. Makes things feel quite sticky. * **Difficult to manage IDs**: Layout animations allow more than one element with a `layoutId` whereas View Transitions will break if the previous element isn't removed. * **Less performant:** View Transitions take an actual screenshot and animate via `width`/`height` vs layout animation's `transform`. This is measurably less performant when animating many elements. * **Doesn't account for scroll**: If the page scroll changes during a view transition, elements will incorrectly animate this delta. * **No relative animations:** If a nested element has a `delay` it will get "left behind" when its parent animates away, whereas Motion handles this kind of relative animation. * **One animation at a time**: View Transitions animate the whole screen, which means combining it with other animations is difficult and other view animations impossible. All-in-all, each system offers something different and each might be a better fit for your needs. In the future it might be that Motion also offers an API based on View Transitions API. --- ## Page: https://motion.dev/docs/react-scroll-animations # Scroll animations There are two types of scroll animations: * **Scroll-triggered:** A normal animation is triggered when an element enters the viewport. * **Scroll-linked:** Values are linked directly to scroll progress. Motion is capable of both types of animation. ## Scroll-triggered animations Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport. Motion offers the `whileInView` prop to set an animation target or variant when the element enters the view. <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} /> ### One-time animations With the `viewport` options, it's possible to set `once: true` so once an element has entered the viewport, it won't animate back out. <motion.div initial\="hidden" whileInView\="visible" viewport\={{ once: true }} /> ### Changing scroll container By default, the element will be considered within the viewport when it enters/leaves the **window**. This can be changed by providing the `ref` of another scrollable element. function Component() { const scrollRef = useRef(null) return ( <div ref\={scrollRef} style\={{ overflow: "scroll" }}\> <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} viewport\={{ root: scrollRef }} /> </div\> ) } For more configuration options, checkout the `motion` component API reference. ### Setting state It's also possible to set state when any element (not just a `motion` component) enters and leaves the viewport with the `useInView` hook. ## Scroll-linked animations Scroll-linked animations are created using motion values and the `useScroll` hook. `useScroll` returns four motion values, two that store scroll offset in pixels (`scrollX` and `scrollY`) and two that store scroll progress as a value between `0` and `1`. These motion values can be passed directly to specific styles. For instance, passing `scrollYProgress` to `scaleX` works great as a progress bar. const { scrollYProgress } = useScroll(); return ( <motion.div style\={{ scaleX: scrollYProgress }} /> ) > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > ~ Sam Selikoff, Motion for React Recipes ### Value smoothing This value can be smoothed by passing it through `useSpring`. const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) return <motion.div style\={{ scaleX }} /> ### Transform other values With the `useTransform` hook, it's easy to use the progress motion values to mix between any value, like colors: const backgroundColor = useTransform( scrollYProgress, \[0, 0.5, 1\], \["#f00", "#0f0", "#00f"\] ) return <motion.div style\={{ backgroundColor }} /> ### Examples #### Track element scroll offset #### Track element within viewport #### Parallax #### 3D #### Scroll velocity and direction Read the full `useScroll` docs to discover more about creating the above effects. There are two types of scroll animations: * **Scroll-triggered:** A normal animation is triggered when an element enters the viewport. * **Scroll-linked:** Values are linked directly to scroll progress. Motion is capable of both types of animation. ## Scroll-triggered animations Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport. Motion offers the `whileInView` prop to set an animation target or variant when the element enters the view. <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} /> ### One-time animations With the `viewport` options, it's possible to set `once: true` so once an element has entered the viewport, it won't animate back out. <motion.div initial\="hidden" whileInView\="visible" viewport\={{ once: true }} /> ### Changing scroll container By default, the element will be considered within the viewport when it enters/leaves the **window**. This can be changed by providing the `ref` of another scrollable element. function Component() { const scrollRef = useRef(null) return ( <div ref\={scrollRef} style\={{ overflow: "scroll" }}\> <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} viewport\={{ root: scrollRef }} /> </div\> ) } For more configuration options, checkout the `motion` component API reference. ### Setting state It's also possible to set state when any element (not just a `motion` component) enters and leaves the viewport with the `useInView` hook. ## Scroll-linked animations Scroll-linked animations are created using motion values and the `useScroll` hook. `useScroll` returns four motion values, two that store scroll offset in pixels (`scrollX` and `scrollY`) and two that store scroll progress as a value between `0` and `1`. These motion values can be passed directly to specific styles. For instance, passing `scrollYProgress` to `scaleX` works great as a progress bar. const { scrollYProgress } = useScroll(); return ( <motion.div style\={{ scaleX: scrollYProgress }} /> ) > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > ~ Sam Selikoff, Motion for React Recipes ### Value smoothing This value can be smoothed by passing it through `useSpring`. const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) return <motion.div style\={{ scaleX }} /> ### Transform other values With the `useTransform` hook, it's easy to use the progress motion values to mix between any value, like colors: const backgroundColor = useTransform( scrollYProgress, \[0, 0.5, 1\], \["#f00", "#0f0", "#00f"\] ) return <motion.div style\={{ backgroundColor }} /> ### Examples #### Track element scroll offset #### Track element within viewport #### Parallax #### 3D #### Scroll velocity and direction Read the full `useScroll` docs to discover more about creating the above effects. There are two types of scroll animations: * **Scroll-triggered:** A normal animation is triggered when an element enters the viewport. * **Scroll-linked:** Values are linked directly to scroll progress. Motion is capable of both types of animation. ## Scroll-triggered animations Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport. Motion offers the `whileInView` prop to set an animation target or variant when the element enters the view. <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} /> ### One-time animations With the `viewport` options, it's possible to set `once: true` so once an element has entered the viewport, it won't animate back out. <motion.div initial\="hidden" whileInView\="visible" viewport\={{ once: true }} /> ### Changing scroll container By default, the element will be considered within the viewport when it enters/leaves the **window**. This can be changed by providing the `ref` of another scrollable element. function Component() { const scrollRef = useRef(null) return ( <div ref\={scrollRef} style\={{ overflow: "scroll" }}\> <motion.div initial\={{ opacity: 0 }} whileInView\={{ opacity: 1 }} viewport\={{ root: scrollRef }} /> </div\> ) } For more configuration options, checkout the `motion` component API reference. ### Setting state It's also possible to set state when any element (not just a `motion` component) enters and leaves the viewport with the `useInView` hook. ## Scroll-linked animations Scroll-linked animations are created using motion values and the `useScroll` hook. `useScroll` returns four motion values, two that store scroll offset in pixels (`scrollX` and `scrollY`) and two that store scroll progress as a value between `0` and `1`. These motion values can be passed directly to specific styles. For instance, passing `scrollYProgress` to `scaleX` works great as a progress bar. const { scrollYProgress } = useScroll(); return ( <motion.div style\={{ scaleX: scrollYProgress }} /> ) > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > ~ Sam Selikoff, Motion for React Recipes ### Value smoothing This value can be smoothed by passing it through `useSpring`. const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) return <motion.div style\={{ scaleX }} /> ### Transform other values With the `useTransform` hook, it's easy to use the progress motion values to mix between any value, like colors: const backgroundColor = useTransform( scrollYProgress, \[0, 0.5, 1\], \["#f00", "#0f0", "#00f"\] ) return <motion.div style\={{ backgroundColor }} /> ### Examples #### Track element scroll offset #### Track element within viewport #### Parallax #### 3D #### Scroll velocity and direction Read the full `useScroll` docs to discover more about creating the above effects. --- ## Page: https://motion.dev/docs/react-transitions # Transitions A `transition` defines the type of animation used when animating between two values. const transition = { duration: 0.8, delay: 0.5, ease: \[0, 0.71, 0.2, 1.01\], } // Motion component <motion.div animate\={{ x: 100 }} transition\={transition} /> // animate() function animate(".box", { x: 100 }, transition) ## Setting a transition `transition` can be set on any animation prop, and that transition will be used when the animation fires. <motion.div whileHover\={{ scale: 1.1, transition: { duration: 0.2 } }} /> ### Value-specific transitions When animating multiple values, each value can be animated with a different transition, with `default` handling all other values: // Motion component <motion.li animate\={{ x: 0, opacity: 1, transition: { default: { type: "spring" }, opacity: { ease: "linear" } } }} /> // animate() function animate("li", { x: 0, opacity: 1 }, { default: { type: "spring" }, opacity: { ease: "linear" } }) ### Default transitions It's possible to set default transitions via the `transition` prop. Either for specific `motion` components: <motion.div animate\={{ x: 100 }} transition\={{ type: "spring", stiffness: 100 }} /> Or for a group of `motion` components via `MotionConfig`: <MotionConfig transition\={{ duration: 0.4, ease: "easeInOut" }}\> <App /> </MotionConfig\> ## Transition settings #### `type` **Default:** Dynamic `type` decides the type of animation to use. It can be `"tween"`, `"spring"` or `"inertia"`. **Tween** animations are set with a duration and an easing curve. **Spring** animations are either physics-based or duration-based. Physics-based spring animations are set via `stiffness`, `damping` and `mass`, and these incorporate the velocity of any existing gestures or animations for natural feedback. Duration-based spring animations are set via a `duration` and `bounce`. These don't incorporate velocity but are easier to understand. **Inertia** animations decelerate a value based on its initial velocity, usually used to implement inertial scrolling. <motion.path animate\={{ pathLength: 1 }} transition\={{ duration: 2, type: "tween" }} /> #### Spring visualiser TimePhysics Duration Bounce Use visual duration ### Tween #### `duration` **Default:** `0.3` (or `0.8` if multiple keyframes are defined) The duration of the animation. Can also be used for `"spring"` animations when `bounce` is also set. animate("ul > li", { opacity: 1 }, { duration: 1 }) #### `ease` The easing function to use with tween animations. Accepts: * Easing function name. E.g `"linear"` * An array of four numbers to define a cubic bezier curve. E.g `[.17,.67,.83,.67]` * A JavaScript easing function, that accepts and returns a value `0`\-`1`. These are the available easing function names: * `"linear"` * `"easeIn"`, `"easeOut"`, `"easeInOut"` * `"circIn"`, `"circOut"`, `"circInOut"` * `"backIn"`, `"backOut"`, `"backInOut"` * `"anticipate"` When animating keyframes, `ease` can optionally be set as an array of easing functions to set different easings between each value: <motion.div animate\={{ x: \[0, 100, 0\], transition: { ease: \["easeIn", "easeOut"\] } }} /> > _I usually use the_ `_"easeOut"_` _curve for enter and exit transitions. The acceleration at the beginning gives the user a feeling of responsiveness. I use a duration no longer than_ `_0.3_`_/_`_0.4_` _seconds to keep the animation fast._~ Emil Kowalski, Animations on the Web #### `times` When animating multiple keyframes, `times` can be used to adjust the position of each keyframe throughout the animation. Each value in `times` is a value between `0` and `1`, representing the start and end of the animation. <motion.div animate\={{ x: \[0, 100, 0\], transition: { times: \[0, 0.3, 1\] } }} /> There must be the same number of `times` as there are keyframes. Defaults to an array of evenly-spread durations. ### Spring #### `bounce` **Default:** `0.25` `bounce` determines the "bounciness" of a spring animation. `0` is no bounce, and `1` is extremely bouncy. **Note:** `bounce` and `duration` will be overridden if `stiffness`, `damping` or `mass` are set. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", bounce: 0.25 }} /> #### `visualDuration` If `visualDuration` is set, this will override `duration`. The visual duration is a time, **set in seconds**, that the animation will take to visually appear to reach its target. In other words, the bulk of the transition will occur before this time, and the "bouncy bit" will mostly happen after. This makes it easier to edit a spring, as well as visually coordinate it with other time-based animations. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", visualDuration: 0.5, bounce: 0.25 }} /> #### `damping` **Default:** `10` Strength of opposing force. If set to 0, spring will oscillate indefinitely. <motion.a animate\={{ rotate: 180 }} transition\={{ type: 'spring', damping: 300 }} /> #### `mass` **Default:** `1` Mass of the moving object. Higher values will result in more lethargic movement. <motion.feTurbulence animate\={{ baseFrequency: 0.5 }} transition\={{ type: "spring", mass: 0.5 }} /> #### `stiffness` **Default:** `1` Stiffness of the spring. Higher values will create more sudden movement. <motion.section animate\={{ rotate: 180 }} transition\={{ type: 'spring', stiffness: 50 }} /> > _I never really understood how_ `_damping_`_,_ `_mass_` _and_ `_stiffness_` _influence a spring animation, so I made a_ _tool for myself_ _to visualise it._~ Emil Kowalski, Animations on the Web #### `velocity` **Default:** Current value velocity The initial velocity of the spring. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', velocity: 2 }} /> #### `restSpeed` **Default:** `0.1` End animation if absolute speed (in units per second) drops below this value and delta is smaller than `restDelta`. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restSpeed: 0.5 }} /> #### `restDelta` **Default:** `0.01` End animation if distance is below this value and speed is below `restSpeed`. When animation ends, the spring will end. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restDelta: 0.5 }} /> ### Inertia An animation that decelerates a value based on its initial velocity. Optionally, `min` and `max` boundaries can be defined, and inertia will snap to these with a spring animation. This animation will automatically precalculate a target value, which can be modified with the `modifyTarget` property. This allows you to add snap-to-grid or similar functionality. Inertia is also the animation used for `dragTransition`, and can be configured via that prop. #### `power` **Default:** `0.8` A higher power value equals a further calculated target. <motion.div drag dragTransition\={{ power: 0.2 }} /> #### `timeConstant` **Default:** `**700**` Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel. <motion.div drag dragTransition\={{ timeConstant: 200 }} /> #### `modifyTarget` A function that receives the automatically-calculated target and returns a new one. Useful for snapping the target to a grid. <motion.div drag // dragTransition always type: inertia dragTransition\={{ power: 0, // Snap calculated target to nearest 50 pixels modifyTarget: target \=> Math.round(target / 50) \* 50 }} /> #### `min` Minimum constraint. If set, the value will "bump" against this value (or immediately spring to it if the animation starts as less than this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `max` Maximum constraint. If set, the value will "bump" against this value (or immediately snap to it, if the initial animation value exceeds this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `bounceStiffness` **Default:** `500` If `min` or `max` is set, this affects the stiffness of the bounce spring. Higher values will create more sudden movement. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> #### `bounceDamping` **Default:** `10` If `min` or `max` is set, this affects the damping of the bounce spring. If set to `0`, spring will oscillate indefinitely. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> ### Orchestration #### `delay` **Default:** `0` Delay the animation by this duration (in seconds). animate(element, { filter: "blur(10px)" }, { delay: 0.3 }) By setting `delay` to a negative value, the animation will start that long into the animation. For instance to start 1 second in, `delay` can be set to -`1`. #### `repeat` **Default:** `0` The number of times to repeat the transition. Set to `Infinity` for perpetual animation. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, duration: 2 }} /> #### `repeatType` **Default:** `"loop"` How to repeat the animation. This can be either: * `loop`: Repeats the animation from the start. * `reverse`: Alternates between forward and backwards playback. * `mirror`: Switches animation origin and target on each iteration. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: 1, repeatType: "reverse", duration: 2 }} /> #### `repeatDelay` **Default:** `0` When repeating an animation, `repeatDelay` will set the duration of the time to wait, in seconds, between each repetition. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, repeatDelay: 1 }} /> #### `when` **Default:** `false` With variants, describes when an animation should trigger, relative to that of its children. * `"beforeChildren"`: Children animations will play after the parent animation finishes. * `"afterChildren"`: Parent animations will play after the children animations finish. const list = { hidden: { opacity: 0, transition: { when: "afterChildren" } } } const item = { hidden: { opacity: 0, transition: { duration: 2 } } } return ( <motion.ul variants\={list} animate\="hidden"\> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `delayChildren` **Default:** `0` With variants, setting `delayChildren` on a parent will delay child animations by this duration (in seconds). const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `staggerChildren` **Default:** `0` With variants, setting `staggerChildren` on a parent will stagger children by this duration. For example, if `staggerChildren` is set to `0.1`, the first child will delayed by `0` seconds, the second by `0.1`, the third by `0.2` etc. The calculated delay will be additional to `delayChildren`. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ol variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ol\> ) #### `staggerDirection` **Default:** `1` The direction in which to stagger children. `1` will stagger from the first to last child, while `-1` staggers from last to first. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5, staggerDirection: -1 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} size\={50} /> <motion.li variants\={item} size\={50} /> </motion.ul\> ) A `transition` defines the type of animation used when animating between two values. const transition = { duration: 0.8, delay: 0.5, ease: \[0, 0.71, 0.2, 1.01\], } // Motion component <motion.div animate\={{ x: 100 }} transition\={transition} /> // animate() function animate(".box", { x: 100 }, transition) ## Setting a transition `transition` can be set on any animation prop, and that transition will be used when the animation fires. <motion.div whileHover\={{ scale: 1.1, transition: { duration: 0.2 } }} /> ### Value-specific transitions When animating multiple values, each value can be animated with a different transition, with `default` handling all other values: // Motion component <motion.li animate\={{ x: 0, opacity: 1, transition: { default: { type: "spring" }, opacity: { ease: "linear" } } }} /> // animate() function animate("li", { x: 0, opacity: 1 }, { default: { type: "spring" }, opacity: { ease: "linear" } }) ### Default transitions It's possible to set default transitions via the `transition` prop. Either for specific `motion` components: <motion.div animate\={{ x: 100 }} transition\={{ type: "spring", stiffness: 100 }} /> Or for a group of `motion` components via `MotionConfig`: <MotionConfig transition\={{ duration: 0.4, ease: "easeInOut" }}\> <App /> </MotionConfig\> ## Transition settings #### `type` **Default:** Dynamic `type` decides the type of animation to use. It can be `"tween"`, `"spring"` or `"inertia"`. **Tween** animations are set with a duration and an easing curve. **Spring** animations are either physics-based or duration-based. Physics-based spring animations are set via `stiffness`, `damping` and `mass`, and these incorporate the velocity of any existing gestures or animations for natural feedback. Duration-based spring animations are set via a `duration` and `bounce`. These don't incorporate velocity but are easier to understand. **Inertia** animations decelerate a value based on its initial velocity, usually used to implement inertial scrolling. <motion.path animate\={{ pathLength: 1 }} transition\={{ duration: 2, type: "tween" }} /> #### Spring visualiser TimePhysics Duration Bounce Use visual duration ### Tween #### `duration` **Default:** `0.3` (or `0.8` if multiple keyframes are defined) The duration of the animation. Can also be used for `"spring"` animations when `bounce` is also set. animate("ul > li", { opacity: 1 }, { duration: 1 }) #### `ease` The easing function to use with tween animations. Accepts: * Easing function name. E.g `"linear"` * An array of four numbers to define a cubic bezier curve. E.g `[.17,.67,.83,.67]` * A JavaScript easing function, that accepts and returns a value `0`\-`1`. These are the available easing function names: * `"linear"` * `"easeIn"`, `"easeOut"`, `"easeInOut"` * `"circIn"`, `"circOut"`, `"circInOut"` * `"backIn"`, `"backOut"`, `"backInOut"` * `"anticipate"` When animating keyframes, `ease` can optionally be set as an array of easing functions to set different easings between each value: <motion.div animate\={{ x: \[0, 100, 0\], transition: { ease: \["easeIn", "easeOut"\] } }} /> > _I usually use the_ `_"easeOut"_` _curve for enter and exit transitions. The acceleration at the beginning gives the user a feeling of responsiveness. I use a duration no longer than_ `_0.3_`_/_`_0.4_` _seconds to keep the animation fast._~ Emil Kowalski, Animations on the Web #### `times` When animating multiple keyframes, `times` can be used to adjust the position of each keyframe throughout the animation. Each value in `times` is a value between `0` and `1`, representing the start and end of the animation. <motion.div animate\={{ x: \[0, 100, 0\], transition: { times: \[0, 0.3, 1\] } }} /> There must be the same number of `times` as there are keyframes. Defaults to an array of evenly-spread durations. ### Spring #### `bounce` **Default:** `0.25` `bounce` determines the "bounciness" of a spring animation. `0` is no bounce, and `1` is extremely bouncy. **Note:** `bounce` and `duration` will be overridden if `stiffness`, `damping` or `mass` are set. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", bounce: 0.25 }} /> #### `visualDuration` If `visualDuration` is set, this will override `duration`. The visual duration is a time, **set in seconds**, that the animation will take to visually appear to reach its target. In other words, the bulk of the transition will occur before this time, and the "bouncy bit" will mostly happen after. This makes it easier to edit a spring, as well as visually coordinate it with other time-based animations. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", visualDuration: 0.5, bounce: 0.25 }} /> #### `damping` **Default:** `10` Strength of opposing force. If set to 0, spring will oscillate indefinitely. <motion.a animate\={{ rotate: 180 }} transition\={{ type: 'spring', damping: 300 }} /> #### `mass` **Default:** `1` Mass of the moving object. Higher values will result in more lethargic movement. <motion.feTurbulence animate\={{ baseFrequency: 0.5 }} transition\={{ type: "spring", mass: 0.5 }} /> #### `stiffness` **Default:** `1` Stiffness of the spring. Higher values will create more sudden movement. <motion.section animate\={{ rotate: 180 }} transition\={{ type: 'spring', stiffness: 50 }} /> > _I never really understood how_ `_damping_`_,_ `_mass_` _and_ `_stiffness_` _influence a spring animation, so I made a_ _tool for myself_ _to visualise it._~ Emil Kowalski, Animations on the Web #### `velocity` **Default:** Current value velocity The initial velocity of the spring. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', velocity: 2 }} /> #### `restSpeed` **Default:** `0.1` End animation if absolute speed (in units per second) drops below this value and delta is smaller than `restDelta`. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restSpeed: 0.5 }} /> #### `restDelta` **Default:** `0.01` End animation if distance is below this value and speed is below `restSpeed`. When animation ends, the spring will end. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restDelta: 0.5 }} /> ### Inertia An animation that decelerates a value based on its initial velocity. Optionally, `min` and `max` boundaries can be defined, and inertia will snap to these with a spring animation. This animation will automatically precalculate a target value, which can be modified with the `modifyTarget` property. This allows you to add snap-to-grid or similar functionality. Inertia is also the animation used for `dragTransition`, and can be configured via that prop. #### `power` **Default:** `0.8` A higher power value equals a further calculated target. <motion.div drag dragTransition\={{ power: 0.2 }} /> #### `timeConstant` **Default:** `**700**` Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel. <motion.div drag dragTransition\={{ timeConstant: 200 }} /> #### `modifyTarget` A function that receives the automatically-calculated target and returns a new one. Useful for snapping the target to a grid. <motion.div drag // dragTransition always type: inertia dragTransition\={{ power: 0, // Snap calculated target to nearest 50 pixels modifyTarget: target \=> Math.round(target / 50) \* 50 }} /> #### `min` Minimum constraint. If set, the value will "bump" against this value (or immediately spring to it if the animation starts as less than this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `max` Maximum constraint. If set, the value will "bump" against this value (or immediately snap to it, if the initial animation value exceeds this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `bounceStiffness` **Default:** `500` If `min` or `max` is set, this affects the stiffness of the bounce spring. Higher values will create more sudden movement. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> #### `bounceDamping` **Default:** `10` If `min` or `max` is set, this affects the damping of the bounce spring. If set to `0`, spring will oscillate indefinitely. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> ### Orchestration #### `delay` **Default:** `0` Delay the animation by this duration (in seconds). animate(element, { filter: "blur(10px)" }, { delay: 0.3 }) By setting `delay` to a negative value, the animation will start that long into the animation. For instance to start 1 second in, `delay` can be set to -`1`. #### `repeat` **Default:** `0` The number of times to repeat the transition. Set to `Infinity` for perpetual animation. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, duration: 2 }} /> #### `repeatType` **Default:** `"loop"` How to repeat the animation. This can be either: * `loop`: Repeats the animation from the start. * `reverse`: Alternates between forward and backwards playback. * `mirror`: Switches animation origin and target on each iteration. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: 1, repeatType: "reverse", duration: 2 }} /> #### `repeatDelay` **Default:** `0` When repeating an animation, `repeatDelay` will set the duration of the time to wait, in seconds, between each repetition. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, repeatDelay: 1 }} /> #### `when` **Default:** `false` With variants, describes when an animation should trigger, relative to that of its children. * `"beforeChildren"`: Children animations will play after the parent animation finishes. * `"afterChildren"`: Parent animations will play after the children animations finish. const list = { hidden: { opacity: 0, transition: { when: "afterChildren" } } } const item = { hidden: { opacity: 0, transition: { duration: 2 } } } return ( <motion.ul variants\={list} animate\="hidden"\> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `delayChildren` **Default:** `0` With variants, setting `delayChildren` on a parent will delay child animations by this duration (in seconds). const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `staggerChildren` **Default:** `0` With variants, setting `staggerChildren` on a parent will stagger children by this duration. For example, if `staggerChildren` is set to `0.1`, the first child will delayed by `0` seconds, the second by `0.1`, the third by `0.2` etc. The calculated delay will be additional to `delayChildren`. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ol variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ol\> ) #### `staggerDirection` **Default:** `1` The direction in which to stagger children. `1` will stagger from the first to last child, while `-1` staggers from last to first. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5, staggerDirection: -1 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} size\={50} /> <motion.li variants\={item} size\={50} /> </motion.ul\> ) A `transition` defines the type of animation used when animating between two values. const transition = { duration: 0.8, delay: 0.5, ease: \[0, 0.71, 0.2, 1.01\], } // Motion component <motion.div animate\={{ x: 100 }} transition\={transition} /> // animate() function animate(".box", { x: 100 }, transition) ## Setting a transition `transition` can be set on any animation prop, and that transition will be used when the animation fires. <motion.div whileHover\={{ scale: 1.1, transition: { duration: 0.2 } }} /> ### Value-specific transitions When animating multiple values, each value can be animated with a different transition, with `default` handling all other values: // Motion component <motion.li animate\={{ x: 0, opacity: 1, transition: { default: { type: "spring" }, opacity: { ease: "linear" } } }} /> // animate() function animate("li", { x: 0, opacity: 1 }, { default: { type: "spring" }, opacity: { ease: "linear" } }) ### Default transitions It's possible to set default transitions via the `transition` prop. Either for specific `motion` components: <motion.div animate\={{ x: 100 }} transition\={{ type: "spring", stiffness: 100 }} /> Or for a group of `motion` components via `MotionConfig`: <MotionConfig transition\={{ duration: 0.4, ease: "easeInOut" }}\> <App /> </MotionConfig\> ## Transition settings #### `type` **Default:** Dynamic `type` decides the type of animation to use. It can be `"tween"`, `"spring"` or `"inertia"`. **Tween** animations are set with a duration and an easing curve. **Spring** animations are either physics-based or duration-based. Physics-based spring animations are set via `stiffness`, `damping` and `mass`, and these incorporate the velocity of any existing gestures or animations for natural feedback. Duration-based spring animations are set via a `duration` and `bounce`. These don't incorporate velocity but are easier to understand. **Inertia** animations decelerate a value based on its initial velocity, usually used to implement inertial scrolling. <motion.path animate\={{ pathLength: 1 }} transition\={{ duration: 2, type: "tween" }} /> #### Spring visualiser TimePhysics Duration Bounce Use visual duration ### Tween #### `duration` **Default:** `0.3` (or `0.8` if multiple keyframes are defined) The duration of the animation. Can also be used for `"spring"` animations when `bounce` is also set. animate("ul > li", { opacity: 1 }, { duration: 1 }) #### `ease` The easing function to use with tween animations. Accepts: * Easing function name. E.g `"linear"` * An array of four numbers to define a cubic bezier curve. E.g `[.17,.67,.83,.67]` * A JavaScript easing function, that accepts and returns a value `0`\-`1`. These are the available easing function names: * `"linear"` * `"easeIn"`, `"easeOut"`, `"easeInOut"` * `"circIn"`, `"circOut"`, `"circInOut"` * `"backIn"`, `"backOut"`, `"backInOut"` * `"anticipate"` When animating keyframes, `ease` can optionally be set as an array of easing functions to set different easings between each value: <motion.div animate\={{ x: \[0, 100, 0\], transition: { ease: \["easeIn", "easeOut"\] } }} /> > _I usually use the_ `_"easeOut"_` _curve for enter and exit transitions. The acceleration at the beginning gives the user a feeling of responsiveness. I use a duration no longer than_ `_0.3_`_/_`_0.4_` _seconds to keep the animation fast._~ Emil Kowalski, Animations on the Web #### `times` When animating multiple keyframes, `times` can be used to adjust the position of each keyframe throughout the animation. Each value in `times` is a value between `0` and `1`, representing the start and end of the animation. <motion.div animate\={{ x: \[0, 100, 0\], transition: { times: \[0, 0.3, 1\] } }} /> There must be the same number of `times` as there are keyframes. Defaults to an array of evenly-spread durations. ### Spring #### `bounce` **Default:** `0.25` `bounce` determines the "bounciness" of a spring animation. `0` is no bounce, and `1` is extremely bouncy. **Note:** `bounce` and `duration` will be overridden if `stiffness`, `damping` or `mass` are set. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", bounce: 0.25 }} /> #### `visualDuration` If `visualDuration` is set, this will override `duration`. The visual duration is a time, **set in seconds**, that the animation will take to visually appear to reach its target. In other words, the bulk of the transition will occur before this time, and the "bouncy bit" will mostly happen after. This makes it easier to edit a spring, as well as visually coordinate it with other time-based animations. <motion.div animate\={{ rotateX: 90 }} transition\={{ type: "spring", visualDuration: 0.5, bounce: 0.25 }} /> #### `damping` **Default:** `10` Strength of opposing force. If set to 0, spring will oscillate indefinitely. <motion.a animate\={{ rotate: 180 }} transition\={{ type: 'spring', damping: 300 }} /> #### `mass` **Default:** `1` Mass of the moving object. Higher values will result in more lethargic movement. <motion.feTurbulence animate\={{ baseFrequency: 0.5 }} transition\={{ type: "spring", mass: 0.5 }} /> #### `stiffness` **Default:** `1` Stiffness of the spring. Higher values will create more sudden movement. <motion.section animate\={{ rotate: 180 }} transition\={{ type: 'spring', stiffness: 50 }} /> > _I never really understood how_ `_damping_`_,_ `_mass_` _and_ `_stiffness_` _influence a spring animation, so I made a_ _tool for myself_ _to visualise it._~ Emil Kowalski, Animations on the Web #### `velocity` **Default:** Current value velocity The initial velocity of the spring. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', velocity: 2 }} /> #### `restSpeed` **Default:** `0.1` End animation if absolute speed (in units per second) drops below this value and delta is smaller than `restDelta`. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restSpeed: 0.5 }} /> #### `restDelta` **Default:** `0.01` End animation if distance is below this value and speed is below `restSpeed`. When animation ends, the spring will end. <motion.div animate\={{ rotate: 180 }} transition\={{ type: 'spring', restDelta: 0.5 }} /> ### Inertia An animation that decelerates a value based on its initial velocity. Optionally, `min` and `max` boundaries can be defined, and inertia will snap to these with a spring animation. This animation will automatically precalculate a target value, which can be modified with the `modifyTarget` property. This allows you to add snap-to-grid or similar functionality. Inertia is also the animation used for `dragTransition`, and can be configured via that prop. #### `power` **Default:** `0.8` A higher power value equals a further calculated target. <motion.div drag dragTransition\={{ power: 0.2 }} /> #### `timeConstant` **Default:** `**700**` Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel. <motion.div drag dragTransition\={{ timeConstant: 200 }} /> #### `modifyTarget` A function that receives the automatically-calculated target and returns a new one. Useful for snapping the target to a grid. <motion.div drag // dragTransition always type: inertia dragTransition\={{ power: 0, // Snap calculated target to nearest 50 pixels modifyTarget: target \=> Math.round(target / 50) \* 50 }} /> #### `min` Minimum constraint. If set, the value will "bump" against this value (or immediately spring to it if the animation starts as less than this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `max` Maximum constraint. If set, the value will "bump" against this value (or immediately snap to it, if the initial animation value exceeds this value). <motion.div drag dragTransition\={{ min: 0, max: 100 }} /> #### `bounceStiffness` **Default:** `500` If `min` or `max` is set, this affects the stiffness of the bounce spring. Higher values will create more sudden movement. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> #### `bounceDamping` **Default:** `10` If `min` or `max` is set, this affects the damping of the bounce spring. If set to `0`, spring will oscillate indefinitely. <motion.div drag dragTransition\={{ min: 0, max: 100, bounceStiffness: 100 }} /> ### Orchestration #### `delay` **Default:** `0` Delay the animation by this duration (in seconds). animate(element, { filter: "blur(10px)" }, { delay: 0.3 }) By setting `delay` to a negative value, the animation will start that long into the animation. For instance to start 1 second in, `delay` can be set to -`1`. #### `repeat` **Default:** `0` The number of times to repeat the transition. Set to `Infinity` for perpetual animation. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, duration: 2 }} /> #### `repeatType` **Default:** `"loop"` How to repeat the animation. This can be either: * `loop`: Repeats the animation from the start. * `reverse`: Alternates between forward and backwards playback. * `mirror`: Switches animation origin and target on each iteration. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: 1, repeatType: "reverse", duration: 2 }} /> #### `repeatDelay` **Default:** `0` When repeating an animation, `repeatDelay` will set the duration of the time to wait, in seconds, between each repetition. <motion.div animate\={{ rotate: 180 }} transition\={{ repeat: Infinity, repeatDelay: 1 }} /> #### `when` **Default:** `false` With variants, describes when an animation should trigger, relative to that of its children. * `"beforeChildren"`: Children animations will play after the parent animation finishes. * `"afterChildren"`: Parent animations will play after the children animations finish. const list = { hidden: { opacity: 0, transition: { when: "afterChildren" } } } const item = { hidden: { opacity: 0, transition: { duration: 2 } } } return ( <motion.ul variants\={list} animate\="hidden"\> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `delayChildren` **Default:** `0` With variants, setting `delayChildren` on a parent will delay child animations by this duration (in seconds). const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ul\> ) #### `staggerChildren` **Default:** `0` With variants, setting `staggerChildren` on a parent will stagger children by this duration. For example, if `staggerChildren` is set to `0.1`, the first child will delayed by `0` seconds, the second by `0.1`, the third by `0.2` etc. The calculated delay will be additional to `delayChildren`. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.5 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ol variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} /> <motion.li variants\={item} /> </motion.ol\> ) #### `staggerDirection` **Default:** `1` The direction in which to stagger children. `1` will stagger from the first to last child, while `-1` staggers from last to first. const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { delayChildren: 0.5, staggerDirection: -1 } } } const item = { hidden: { opacity: 0 }, show: { opacity: 1 } } return ( <motion.ul variants\={container} initial\="hidden" animate\="show" \> <motion.li variants\={item} size\={50} /> <motion.li variants\={item} size\={50} /> </motion.ul\> ) --- ## Page: https://motion.dev/docs/react-motion-component # 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/react-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}\` } /> 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/react-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}\` } /> 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/react-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}\` } /> --- ## Page: https://motion.dev/docs/react-animate-number # AnimateNumber Motion+ Exclusive Checking Motion+ status… This content is exclusive to Motion+ members Get Motion+ for instant access One-time payment, no subscription Already joined? Login Checking Motion+ status… This content is exclusive to Motion+ members Get Motion+ for instant access One-time payment, no subscription Already joined? Login Checking Motion+ status… This content is exclusive to Motion+ members Get Motion+ for instant access One-time payment, no subscription Already joined? Login `AnimateNumber` creates beautiful number animations with Motion. <AnimateNumber\>{count}</AnimateNumber\> You can create a number of popular animation effects, like countdowns, engagement bars, or labelling user inputs. It's a continuation of the original version of Max Barvian's NumberFlow component, which was built on Motion. Because `AnimateNumber` leverages Motion's existing layout animations, it's only 2.5kb on top of Motion for React. It also means you can use Motion's existing transition settings. However, being based on an older version of NumberFlow means it currently lacks a couple of its newer props like `trend` and `plugins`. In this guide, we'll learn how to install `AnimateNumber` into our projects, and how to use it for a variety of number animation effects. --- ## Page: https://motion.dev/docs/react-animate-presence # AnimatePresence `AnimatePresence` makes exit animations easy. By wrapping one or more `motion` components with `AnimatePresence`, we gain access to the `exit` animation prop. <AnimatePresence\> {show && <motion.div key\="modal" exit\={{ opacity: 0 }} />} </AnimatePresence\> ## Usage ### Import import { AnimatePresence } from "motion/react" ### Exit animations `AnimatePresence` works by detecting when its **direct children** are removed from the React tree. This can be due to a component mounting/remounting: <AnimatePresence\> {show && <Modal key\="modal" />} </AnimatePresence\> Its `key` changing: <AnimatePresence\> <Slide key\={activeItem.id} /> </AnimatePresence\> Or when children in a list are added/removed: <AnimatePresence\> {items.map(item \=> ( <motion.li key\={item.id} exit\={{ opacity: 1 }} layout /> ))} </AnimatePresence\> Any `motion` components within the exiting component will fire animations defined on their `exit` props before the component is removed from the DOM. function Slide({ img, description }) { return ( <motion.div exit\={{ opacity: 0 }}\> <img src\={img.src} /> <motion.p exit\={{ y: 10 }}\>{description}</motion.p\> </motion.div\> ) } **Note:** Direct children must each have a unique `key` prop so `AnimatePresence` can track their presence in the tree. Like `initial` and `animate`, `exit` can be defined either as an object of values, or as a variant label. const modalVariants = { visible: { opacity: 1, transition: { when: "beforeChildren" } }, hidden: { opacity: 0, transition: { when: "afterChildren" } } } function Modal({ children }) { return ( <motion.div initial\="hidden" animate\="visible" exit\="hidden"\> {children} </motion.div\> ) } ### Changing `key` Changing a `key` prop makes React create an entirely new component. So by changing the `key` of a single child of `AnimatePresence`, we can easily make components like slideshows. export const Slideshow = ({ image }) \=> ( <AnimatePresence\> <motion.img key\={image.src} src\={image.src} initial\={{ x: 300, opacity: 0 }} animate\={{ x: 0, opacity: 1 }} exit\={{ x: -300, opacity: 0 }} /> </AnimatePresence\> ) ### Access presence state Any child of `AnimatePresence` can access presence state with the `useIsPresence` hook. import { useIsPresent } from "motion/react" function Component() { const isPresent = useIsPresent() return isPresent ? "Here!" : "Exiting..." } This allows you to change content or styles when a component is no longer rendered. ### Access presence data When a component has been removed from the React tree, its props can no longer be updated. We can use `AnimatePresence`'s `custom` prop to pass new data down through the tree, even into exiting components. <AnimatePresence custom\={swipeDirection}\> <Slide key\={activeSlideId}\> Then later we can extract that using `usePresenceData`. import { AnimatePresence, usePresenceData } from "motion/react" function Slide() { const isPresent = useIsPresent() const direction = usePresenceData() return ( <motion.div exit\={{ opacity: 0 }}\> {isPresent ? "Here!" : "Exiting " + direction} </motion.div\> ) } ### Manual usage It's also possible to manually tell `AnimatePresence` when a component is safe to remove with the `usePresence` hook. This returns both `isPresent` state and a callback, `safeToRemove`, that should be called when you're ready to remove the component from the DOM (for instance after a manual animation or other timeout). import { usePresence } from "motion/react" function Component() { const \[isPresent, safeToRemove\] = usePresence() useEffect(() \=> { // Remove from DOM 1000ms after being removed from React !isPresent && setTimeout(safeToRemove, 1000) }, \[isPresent\]) return <div /> } ### Propagate exit animations By default, `AnimatePresence` controls the `exit` animations on all of its children, **until** another `AnimatePresence` component is rendered. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children will not fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> By setting an `AnimatePresence` component's `propagate` prop to `true`, when it's removed from another `AnimatePresence` it will fire all of **its** children's exit animations. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children \*\*will\*\* fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Props ### `initial` By passing `initial={false}`, `AnimatePresence` will disable any initial animations on children that are present when the component is first rendered. <AnimatePresence initial\={false}\> <Slide key\={activeItem.id} /> </AnimatePresence\> ### `custom` When a component is removed, there's no longer a chance to update its props (because it's no longer in the React tree). Therefore we can't update its exit animation with the same render that removed the component. By passing a value through `AnimatePresence`'s `custom` prop, we can use dynamic variants to change the `exit` animation. const variants = { hidden: (direction) \=> ({ opacity: 0, x: direction === 1 ? -300 : 300 }), visible: { opacity: 1, x: 0 } } export const Slideshow = ({ image, direction }) \=> ( <AnimatePresence custom\={direction}\> <motion.img key\={image.src} src\={image.src} variants\={variants} initial\="hidden" animate\="visible" exit\="hidden" /> </AnimatePresence\> ) This data can be accessed by children via `usePresenceData`. ### `mode` **Default:** `"sync"` Decides how `AnimatePresence` handles entering and exiting children. * `"sync"`: Children animate in/out as soon as they're added/removed. * `"wait"`: The entering child will wait until the exiting child has animated out. **Note:** Currently only renders a single child at a time. * `"popLayout"`: Exiting children will be "popped" out of the page layout. This allows surrounding elements to move to their new layout immediately. **Custom component note:** When using `popLayout` mode, any immediate child of AnimatePresence that's a custom component **must** be wrapped in React's `forwardRef` function, forwarding the provided `ref` to the DOM node you wish to pop out of the layout. ### `onExitComplete` Fires when all exiting nodes have completed animating out. ### `propagate` **Default:** `false` If set to `true`, exit animations on children will also trigger when this `AnimatePresence` exits from a parent `AnimatePresence`. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* This exit prop will now fire when show is false \*/} <motion.div exit\={{ x: -100 }} /> </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Troubleshooting ### Exit animations aren't working Ensure all **immediate** children get a unique `key` prop that **remains the same for that component every render**. For instance, providing `index` as a `key` is **bad** because if the items reorder then the `index` will not be matched to the `item`: <AnimatePresence\> {items.map((item, index) \=> ( <Component key\={index} /> ))} </AnimatePresence\> It's preferred to pass something that's unique to that item, for instance an ID: <AnimatePresence\> {items.map((item) \=> ( <Component key\={item.id} /> ))} </AnimatePresence\> Also make sure `AnimatePresence` is **outside** of the code that unmounts the element. If `AnimatePresence` itself unmounts, then it can't control exit animations! For example, this will **not work**: isVisible && ( <AnimatePresence\> <Component /> </AnimatePresence\> ) Instead, the conditional should be at the root of `AnimatePresence`: <AnimatePresence\> {isVisible && <Component />} </AnimatePresence\> ### Layout animations not working with `mode="sync"` When mixing layout and exit animations, it might be necessary to wrap the group in `LayoutGroup` to ensure that components outside of `AnimatePresence` know when to perform a layout animation. <LayoutGroup\> <motion.ul layout\> <AnimatePresence\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> </LayoutGroup\> ### Layout animations not working with `mode="popLayout"` When any HTML element has an active `transform` it temporarily becomes the offset parent of its children. This can cause children with `position: "absolute"` not to appear where you expect. `mode="popLayout"` works by using `position: "absolute"`. So to ensure consistent and expected positioning during a layout animation, ensure that the animating parent has a `position` other than `"static"`. <motion.ul layout style\={{ position: "relative" }}\> <AnimatePresence mode\="popLayout"\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> `AnimatePresence` makes exit animations easy. By wrapping one or more `motion` components with `AnimatePresence`, we gain access to the `exit` animation prop. <AnimatePresence\> {show && <motion.div key\="modal" exit\={{ opacity: 0 }} />} </AnimatePresence\> ## Usage ### Import import { AnimatePresence } from "motion/react" ### Exit animations `AnimatePresence` works by detecting when its **direct children** are removed from the React tree. This can be due to a component mounting/remounting: <AnimatePresence\> {show && <Modal key\="modal" />} </AnimatePresence\> Its `key` changing: <AnimatePresence\> <Slide key\={activeItem.id} /> </AnimatePresence\> Or when children in a list are added/removed: <AnimatePresence\> {items.map(item \=> ( <motion.li key\={item.id} exit\={{ opacity: 1 }} layout /> ))} </AnimatePresence\> Any `motion` components within the exiting component will fire animations defined on their `exit` props before the component is removed from the DOM. function Slide({ img, description }) { return ( <motion.div exit\={{ opacity: 0 }}\> <img src\={img.src} /> <motion.p exit\={{ y: 10 }}\>{description}</motion.p\> </motion.div\> ) } **Note:** Direct children must each have a unique `key` prop so `AnimatePresence` can track their presence in the tree. Like `initial` and `animate`, `exit` can be defined either as an object of values, or as a variant label. const modalVariants = { visible: { opacity: 1, transition: { when: "beforeChildren" } }, hidden: { opacity: 0, transition: { when: "afterChildren" } } } function Modal({ children }) { return ( <motion.div initial\="hidden" animate\="visible" exit\="hidden"\> {children} </motion.div\> ) } ### Changing `key` Changing a `key` prop makes React create an entirely new component. So by changing the `key` of a single child of `AnimatePresence`, we can easily make components like slideshows. export const Slideshow = ({ image }) \=> ( <AnimatePresence\> <motion.img key\={image.src} src\={image.src} initial\={{ x: 300, opacity: 0 }} animate\={{ x: 0, opacity: 1 }} exit\={{ x: -300, opacity: 0 }} /> </AnimatePresence\> ) ### Access presence state Any child of `AnimatePresence` can access presence state with the `useIsPresence` hook. import { useIsPresent } from "motion/react" function Component() { const isPresent = useIsPresent() return isPresent ? "Here!" : "Exiting..." } This allows you to change content or styles when a component is no longer rendered. ### Access presence data When a component has been removed from the React tree, its props can no longer be updated. We can use `AnimatePresence`'s `custom` prop to pass new data down through the tree, even into exiting components. <AnimatePresence custom\={swipeDirection}\> <Slide key\={activeSlideId}\> Then later we can extract that using `usePresenceData`. import { AnimatePresence, usePresenceData } from "motion/react" function Slide() { const isPresent = useIsPresent() const direction = usePresenceData() return ( <motion.div exit\={{ opacity: 0 }}\> {isPresent ? "Here!" : "Exiting " + direction} </motion.div\> ) } ### Manual usage It's also possible to manually tell `AnimatePresence` when a component is safe to remove with the `usePresence` hook. This returns both `isPresent` state and a callback, `safeToRemove`, that should be called when you're ready to remove the component from the DOM (for instance after a manual animation or other timeout). import { usePresence } from "motion/react" function Component() { const \[isPresent, safeToRemove\] = usePresence() useEffect(() \=> { // Remove from DOM 1000ms after being removed from React !isPresent && setTimeout(safeToRemove, 1000) }, \[isPresent\]) return <div /> } ### Propagate exit animations By default, `AnimatePresence` controls the `exit` animations on all of its children, **until** another `AnimatePresence` component is rendered. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children will not fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> By setting an `AnimatePresence` component's `propagate` prop to `true`, when it's removed from another `AnimatePresence` it will fire all of **its** children's exit animations. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children \*\*will\*\* fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Props ### `initial` By passing `initial={false}`, `AnimatePresence` will disable any initial animations on children that are present when the component is first rendered. <AnimatePresence initial\={false}\> <Slide key\={activeItem.id} /> </AnimatePresence\> ### `custom` When a component is removed, there's no longer a chance to update its props (because it's no longer in the React tree). Therefore we can't update its exit animation with the same render that removed the component. By passing a value through `AnimatePresence`'s `custom` prop, we can use dynamic variants to change the `exit` animation. const variants = { hidden: (direction) \=> ({ opacity: 0, x: direction === 1 ? -300 : 300 }), visible: { opacity: 1, x: 0 } } export const Slideshow = ({ image, direction }) \=> ( <AnimatePresence custom\={direction}\> <motion.img key\={image.src} src\={image.src} variants\={variants} initial\="hidden" animate\="visible" exit\="hidden" /> </AnimatePresence\> ) This data can be accessed by children via `usePresenceData`. ### `mode` **Default:** `"sync"` Decides how `AnimatePresence` handles entering and exiting children. * `"sync"`: Children animate in/out as soon as they're added/removed. * `"wait"`: The entering child will wait until the exiting child has animated out. **Note:** Currently only renders a single child at a time. * `"popLayout"`: Exiting children will be "popped" out of the page layout. This allows surrounding elements to move to their new layout immediately. **Custom component note:** When using `popLayout` mode, any immediate child of AnimatePresence that's a custom component **must** be wrapped in React's `forwardRef` function, forwarding the provided `ref` to the DOM node you wish to pop out of the layout. ### `onExitComplete` Fires when all exiting nodes have completed animating out. ### `propagate` **Default:** `false` If set to `true`, exit animations on children will also trigger when this `AnimatePresence` exits from a parent `AnimatePresence`. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* This exit prop will now fire when show is false \*/} <motion.div exit\={{ x: -100 }} /> </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Troubleshooting ### Exit animations aren't working Ensure all **immediate** children get a unique `key` prop that **remains the same for that component every render**. For instance, providing `index` as a `key` is **bad** because if the items reorder then the `index` will not be matched to the `item`: <AnimatePresence\> {items.map((item, index) \=> ( <Component key\={index} /> ))} </AnimatePresence\> It's preferred to pass something that's unique to that item, for instance an ID: <AnimatePresence\> {items.map((item) \=> ( <Component key\={item.id} /> ))} </AnimatePresence\> Also make sure `AnimatePresence` is **outside** of the code that unmounts the element. If `AnimatePresence` itself unmounts, then it can't control exit animations! For example, this will **not work**: isVisible && ( <AnimatePresence\> <Component /> </AnimatePresence\> ) Instead, the conditional should be at the root of `AnimatePresence`: <AnimatePresence\> {isVisible && <Component />} </AnimatePresence\> ### Layout animations not working with `mode="sync"` When mixing layout and exit animations, it might be necessary to wrap the group in `LayoutGroup` to ensure that components outside of `AnimatePresence` know when to perform a layout animation. <LayoutGroup\> <motion.ul layout\> <AnimatePresence\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> </LayoutGroup\> ### Layout animations not working with `mode="popLayout"` When any HTML element has an active `transform` it temporarily becomes the offset parent of its children. This can cause children with `position: "absolute"` not to appear where you expect. `mode="popLayout"` works by using `position: "absolute"`. So to ensure consistent and expected positioning during a layout animation, ensure that the animating parent has a `position` other than `"static"`. <motion.ul layout style\={{ position: "relative" }}\> <AnimatePresence mode\="popLayout"\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> `AnimatePresence` makes exit animations easy. By wrapping one or more `motion` components with `AnimatePresence`, we gain access to the `exit` animation prop. <AnimatePresence\> {show && <motion.div key\="modal" exit\={{ opacity: 0 }} />} </AnimatePresence\> ## Usage ### Import import { AnimatePresence } from "motion/react" ### Exit animations `AnimatePresence` works by detecting when its **direct children** are removed from the React tree. This can be due to a component mounting/remounting: <AnimatePresence\> {show && <Modal key\="modal" />} </AnimatePresence\> Its `key` changing: <AnimatePresence\> <Slide key\={activeItem.id} /> </AnimatePresence\> Or when children in a list are added/removed: <AnimatePresence\> {items.map(item \=> ( <motion.li key\={item.id} exit\={{ opacity: 1 }} layout /> ))} </AnimatePresence\> Any `motion` components within the exiting component will fire animations defined on their `exit` props before the component is removed from the DOM. function Slide({ img, description }) { return ( <motion.div exit\={{ opacity: 0 }}\> <img src\={img.src} /> <motion.p exit\={{ y: 10 }}\>{description}</motion.p\> </motion.div\> ) } **Note:** Direct children must each have a unique `key` prop so `AnimatePresence` can track their presence in the tree. Like `initial` and `animate`, `exit` can be defined either as an object of values, or as a variant label. const modalVariants = { visible: { opacity: 1, transition: { when: "beforeChildren" } }, hidden: { opacity: 0, transition: { when: "afterChildren" } } } function Modal({ children }) { return ( <motion.div initial\="hidden" animate\="visible" exit\="hidden"\> {children} </motion.div\> ) } ### Changing `key` Changing a `key` prop makes React create an entirely new component. So by changing the `key` of a single child of `AnimatePresence`, we can easily make components like slideshows. export const Slideshow = ({ image }) \=> ( <AnimatePresence\> <motion.img key\={image.src} src\={image.src} initial\={{ x: 300, opacity: 0 }} animate\={{ x: 0, opacity: 1 }} exit\={{ x: -300, opacity: 0 }} /> </AnimatePresence\> ) ### Access presence state Any child of `AnimatePresence` can access presence state with the `useIsPresence` hook. import { useIsPresent } from "motion/react" function Component() { const isPresent = useIsPresent() return isPresent ? "Here!" : "Exiting..." } This allows you to change content or styles when a component is no longer rendered. ### Access presence data When a component has been removed from the React tree, its props can no longer be updated. We can use `AnimatePresence`'s `custom` prop to pass new data down through the tree, even into exiting components. <AnimatePresence custom\={swipeDirection}\> <Slide key\={activeSlideId}\> Then later we can extract that using `usePresenceData`. import { AnimatePresence, usePresenceData } from "motion/react" function Slide() { const isPresent = useIsPresent() const direction = usePresenceData() return ( <motion.div exit\={{ opacity: 0 }}\> {isPresent ? "Here!" : "Exiting " + direction} </motion.div\> ) } ### Manual usage It's also possible to manually tell `AnimatePresence` when a component is safe to remove with the `usePresence` hook. This returns both `isPresent` state and a callback, `safeToRemove`, that should be called when you're ready to remove the component from the DOM (for instance after a manual animation or other timeout). import { usePresence } from "motion/react" function Component() { const \[isPresent, safeToRemove\] = usePresence() useEffect(() \=> { // Remove from DOM 1000ms after being removed from React !isPresent && setTimeout(safeToRemove, 1000) }, \[isPresent\]) return <div /> } ### Propagate exit animations By default, `AnimatePresence` controls the `exit` animations on all of its children, **until** another `AnimatePresence` component is rendered. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children will not fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> By setting an `AnimatePresence` component's `propagate` prop to `true`, when it's removed from another `AnimatePresence` it will fire all of **its** children's exit animations. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* \* When \`show\` becomes \`false\`, exit animations \* on these children \*\*will\*\* fire. \*/} {children} </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Props ### `initial` By passing `initial={false}`, `AnimatePresence` will disable any initial animations on children that are present when the component is first rendered. <AnimatePresence initial\={false}\> <Slide key\={activeItem.id} /> </AnimatePresence\> ### `custom` When a component is removed, there's no longer a chance to update its props (because it's no longer in the React tree). Therefore we can't update its exit animation with the same render that removed the component. By passing a value through `AnimatePresence`'s `custom` prop, we can use dynamic variants to change the `exit` animation. const variants = { hidden: (direction) \=> ({ opacity: 0, x: direction === 1 ? -300 : 300 }), visible: { opacity: 1, x: 0 } } export const Slideshow = ({ image, direction }) \=> ( <AnimatePresence custom\={direction}\> <motion.img key\={image.src} src\={image.src} variants\={variants} initial\="hidden" animate\="visible" exit\="hidden" /> </AnimatePresence\> ) This data can be accessed by children via `usePresenceData`. ### `mode` **Default:** `"sync"` Decides how `AnimatePresence` handles entering and exiting children. * `"sync"`: Children animate in/out as soon as they're added/removed. * `"wait"`: The entering child will wait until the exiting child has animated out. **Note:** Currently only renders a single child at a time. * `"popLayout"`: Exiting children will be "popped" out of the page layout. This allows surrounding elements to move to their new layout immediately. **Custom component note:** When using `popLayout` mode, any immediate child of AnimatePresence that's a custom component **must** be wrapped in React's `forwardRef` function, forwarding the provided `ref` to the DOM node you wish to pop out of the layout. ### `onExitComplete` Fires when all exiting nodes have completed animating out. ### `propagate` **Default:** `false` If set to `true`, exit animations on children will also trigger when this `AnimatePresence` exits from a parent `AnimatePresence`. <AnimatePresence\> {show ? ( <motion.section exit\={{ opacity: 0 }}\> <AnimatePresence propagate\> {/\* This exit prop will now fire when show is false \*/} <motion.div exit\={{ x: -100 }} /> </AnimatePresence\> </motion.section\> ) : null} </AnimatePresence\> ## Troubleshooting ### Exit animations aren't working Ensure all **immediate** children get a unique `key` prop that **remains the same for that component every render**. For instance, providing `index` as a `key` is **bad** because if the items reorder then the `index` will not be matched to the `item`: <AnimatePresence\> {items.map((item, index) \=> ( <Component key\={index} /> ))} </AnimatePresence\> It's preferred to pass something that's unique to that item, for instance an ID: <AnimatePresence\> {items.map((item) \=> ( <Component key\={item.id} /> ))} </AnimatePresence\> Also make sure `AnimatePresence` is **outside** of the code that unmounts the element. If `AnimatePresence` itself unmounts, then it can't control exit animations! For example, this will **not work**: isVisible && ( <AnimatePresence\> <Component /> </AnimatePresence\> ) Instead, the conditional should be at the root of `AnimatePresence`: <AnimatePresence\> {isVisible && <Component />} </AnimatePresence\> ### Layout animations not working with `mode="sync"` When mixing layout and exit animations, it might be necessary to wrap the group in `LayoutGroup` to ensure that components outside of `AnimatePresence` know when to perform a layout animation. <LayoutGroup\> <motion.ul layout\> <AnimatePresence\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> </LayoutGroup\> ### Layout animations not working with `mode="popLayout"` When any HTML element has an active `transform` it temporarily becomes the offset parent of its children. This can cause children with `position: "absolute"` not to appear where you expect. `mode="popLayout"` works by using `position: "absolute"`. So to ensure consistent and expected positioning during a layout animation, ensure that the animating parent has a `position` other than `"static"`. <motion.ul layout style\={{ position: "relative" }}\> <AnimatePresence mode\="popLayout"\> {items.map(item \=> ( <motion.li layout key\={item.id} /> ))} </AnimatePresence\> </motion.ul\> --- ## Page: https://motion.dev/docs/react-layout-group # LayoutGroup `motion` components with a `layout` prop will detect and animate layout changes every time they commit a React re-render, or their `layoutDependency` prop changes. `LayoutGroup` is used to group components that might not render together but do affect each-other's state. ## Usage Take these accordion items that each handle their own state: function Item({ header, content }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.div layout onClick\={() \=> setIsOpen(!isOpen)} \> <motion.h2 layout\>{header}</motion.h2\> {isOpen ? content : null} </motion.div\> ) } If we arrange these next to each other in an `Accordion`, when their state updates, their siblings have no way of knowing: function Accordion() { return ( <\> <ToggleContent /> <ToggleContent /> </\> ) } This can be fixed by grouping both components with `LayoutGroup`: import { LayoutGroup } from "motion/react" function Accordion() { return ( <LayoutGroup\> <ToggleContent /> <ToggleContent /> </LayoutGroup\> ) } ### Namespace `layoutId` Components expecting to perform shared layout animations are provided a `layoutId` prop. In this following example, each `Tab` renders an element with the `layoutId="underline"` prop. function Tab({ label, isSelected }) { return ( <li\> {label} {isSelected ? <motion.div layoutId\="underline" /> : null} </li\> ) } function TabRow({ items }) { return items.map(item \=> <Tab {...item} />) } `layoutId` is global across your site. So to render multiple `TabRow`s we want to group them with `LayoutGroup` and `id` prop: function TabRow({ id, items }) { return ( <LayoutGroup id\={id}\> {items.map(item \=> <Tab {...item} />)} </LayoutGroup\> } `motion` components with a `layout` prop will detect and animate layout changes every time they commit a React re-render, or their `layoutDependency` prop changes. `LayoutGroup` is used to group components that might not render together but do affect each-other's state. ## Usage Take these accordion items that each handle their own state: function Item({ header, content }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.div layout onClick\={() \=> setIsOpen(!isOpen)} \> <motion.h2 layout\>{header}</motion.h2\> {isOpen ? content : null} </motion.div\> ) } If we arrange these next to each other in an `Accordion`, when their state updates, their siblings have no way of knowing: function Accordion() { return ( <\> <ToggleContent /> <ToggleContent /> </\> ) } This can be fixed by grouping both components with `LayoutGroup`: import { LayoutGroup } from "motion/react" function Accordion() { return ( <LayoutGroup\> <ToggleContent /> <ToggleContent /> </LayoutGroup\> ) } ### Namespace `layoutId` Components expecting to perform shared layout animations are provided a `layoutId` prop. In this following example, each `Tab` renders an element with the `layoutId="underline"` prop. function Tab({ label, isSelected }) { return ( <li\> {label} {isSelected ? <motion.div layoutId\="underline" /> : null} </li\> ) } function TabRow({ items }) { return items.map(item \=> <Tab {...item} />) } `layoutId` is global across your site. So to render multiple `TabRow`s we want to group them with `LayoutGroup` and `id` prop: function TabRow({ id, items }) { return ( <LayoutGroup id\={id}\> {items.map(item \=> <Tab {...item} />)} </LayoutGroup\> } `motion` components with a `layout` prop will detect and animate layout changes every time they commit a React re-render, or their `layoutDependency` prop changes. `LayoutGroup` is used to group components that might not render together but do affect each-other's state. ## Usage Take these accordion items that each handle their own state: function Item({ header, content }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.div layout onClick\={() \=> setIsOpen(!isOpen)} \> <motion.h2 layout\>{header}</motion.h2\> {isOpen ? content : null} </motion.div\> ) } If we arrange these next to each other in an `Accordion`, when their state updates, their siblings have no way of knowing: function Accordion() { return ( <\> <ToggleContent /> <ToggleContent /> </\> ) } This can be fixed by grouping both components with `LayoutGroup`: import { LayoutGroup } from "motion/react" function Accordion() { return ( <LayoutGroup\> <ToggleContent /> <ToggleContent /> </LayoutGroup\> ) } ### Namespace `layoutId` Components expecting to perform shared layout animations are provided a `layoutId` prop. In this following example, each `Tab` renders an element with the `layoutId="underline"` prop. function Tab({ label, isSelected }) { return ( <li\> {label} {isSelected ? <motion.div layoutId\="underline" /> : null} </li\> ) } function TabRow({ items }) { return items.map(item \=> <Tab {...item} />) } `layoutId` is global across your site. So to render multiple `TabRow`s we want to group them with `LayoutGroup` and `id` prop: function TabRow({ id, items }) { return ( <LayoutGroup id\={id}\> {items.map(item \=> <Tab {...item} />)} </LayoutGroup\> } --- ## Page: https://motion.dev/docs/react-lazy-motion # LazyMotion For ease of use, the `motion` component comes pre-bundled with all of its features for a bundlesize of around 34kb. With `LazyMotion` and the `m` component, we can reduce this to 6kb for the initial render and then sync or async load a subset of features. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) Read the Reduce bundle size guide for full usage instructions. ## Props ### `features` Define a feature bundle to load sync or async. #### Sync loading Synchronous loading is useful for defining a subset of functionality for a smaller bundlesize. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Async loading Asynchronous loading can ensure your site is hydrated before loading in some or all animation functionality. // features.js import { domAnimations } from "motion/react" export default domAnimations // index.js const loadFeatures = import("./features.js") .then(res \=> res.default) function Component() { return ( <LazyMotion features\={loadFeatures}\> <m.div animate\={{ scale: 1.5 }} /> </LazyMotion\> ) } ### `strict` **Default:** `false` If `true`, will throw an error if a `motion` component renders within a `LazyMotion` component (thereby removing the bundlesize benefits of lazy-loading). // This component will throw an error that explains using a motion component // instead of the m component will break the benefits of code-splitting. function Component() { return ( <LazyMotion features\={domAnimations} strict\> <motion.div /> </LazyMotion\> ) } For ease of use, the `motion` component comes pre-bundled with all of its features for a bundlesize of around 34kb. With `LazyMotion` and the `m` component, we can reduce this to 6kb for the initial render and then sync or async load a subset of features. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) Read the Reduce bundle size guide for full usage instructions. ## Props ### `features` Define a feature bundle to load sync or async. #### Sync loading Synchronous loading is useful for defining a subset of functionality for a smaller bundlesize. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Async loading Asynchronous loading can ensure your site is hydrated before loading in some or all animation functionality. // features.js import { domAnimations } from "motion/react" export default domAnimations // index.js const loadFeatures = import("./features.js") .then(res \=> res.default) function Component() { return ( <LazyMotion features\={loadFeatures}\> <m.div animate\={{ scale: 1.5 }} /> </LazyMotion\> ) } ### `strict` **Default:** `false` If `true`, will throw an error if a `motion` component renders within a `LazyMotion` component (thereby removing the bundlesize benefits of lazy-loading). // This component will throw an error that explains using a motion component // instead of the m component will break the benefits of code-splitting. function Component() { return ( <LazyMotion features\={domAnimations} strict\> <motion.div /> </LazyMotion\> ) } For ease of use, the `motion` component comes pre-bundled with all of its features for a bundlesize of around 34kb. With `LazyMotion` and the `m` component, we can reduce this to 6kb for the initial render and then sync or async load a subset of features. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) Read the Reduce bundle size guide for full usage instructions. ## Props ### `features` Define a feature bundle to load sync or async. #### Sync loading Synchronous loading is useful for defining a subset of functionality for a smaller bundlesize. import { LazyMotion, domAnimations } from "motion/react" import \* as m from "motion/react-m" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimations}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Async loading Asynchronous loading can ensure your site is hydrated before loading in some or all animation functionality. // features.js import { domAnimations } from "motion/react" export default domAnimations // index.js const loadFeatures = import("./features.js") .then(res \=> res.default) function Component() { return ( <LazyMotion features\={loadFeatures}\> <m.div animate\={{ scale: 1.5 }} /> </LazyMotion\> ) } ### `strict` **Default:** `false` If `true`, will throw an error if a `motion` component renders within a `LazyMotion` component (thereby removing the bundlesize benefits of lazy-loading). // This component will throw an error that explains using a motion component // instead of the m component will break the benefits of code-splitting. function Component() { return ( <LazyMotion features\={domAnimations} strict\> <motion.div /> </LazyMotion\> ) } --- ## Page: https://motion.dev/docs/react-motion-config # MotionConfig The `MotionConfig` component can be used to set configuration options for all child `motion` components. import { motion, MotionConfig } from "motion/react" export const MyComponent = ({ isVisible }) \=> ( <MotionConfig transition\={{ duration: 1 }}\> <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </MotionConfig\> ) ## Props ### `transition` Define a fallback `transition` to use for all child `motion` components. ### `reducedMotion` **Default:** `"never"` `reducedMotion` lets you set a site-wide policy for handling reduced motion. It offers the following options: * `"user"`: Respect the user's device setting. * `"always"`: Enforce reduced motion (useful for debugging). * `"never"`: Don't respect reduced motion. When reduced motion is on, transform and layout animations will be disabled. Other animations, like `opacity` and `backgroundColor`, will persist. ### `nonce` If using a Content Security Policy with a `nonce` attribute, passing the same attribute through `MotionConfig` will allow any `style` blocks generated by Motion to adhere the the security policy. The `MotionConfig` component can be used to set configuration options for all child `motion` components. import { motion, MotionConfig } from "motion/react" export const MyComponent = ({ isVisible }) \=> ( <MotionConfig transition\={{ duration: 1 }}\> <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </MotionConfig\> ) ## Props ### `transition` Define a fallback `transition` to use for all child `motion` components. ### `reducedMotion` **Default:** `"never"` `reducedMotion` lets you set a site-wide policy for handling reduced motion. It offers the following options: * `"user"`: Respect the user's device setting. * `"always"`: Enforce reduced motion (useful for debugging). * `"never"`: Don't respect reduced motion. When reduced motion is on, transform and layout animations will be disabled. Other animations, like `opacity` and `backgroundColor`, will persist. ### `nonce` If using a Content Security Policy with a `nonce` attribute, passing the same attribute through `MotionConfig` will allow any `style` blocks generated by Motion to adhere the the security policy. The `MotionConfig` component can be used to set configuration options for all child `motion` components. import { motion, MotionConfig } from "motion/react" export const MyComponent = ({ isVisible }) \=> ( <MotionConfig transition\={{ duration: 1 }}\> <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </MotionConfig\> ) ## Props ### `transition` Define a fallback `transition` to use for all child `motion` components. ### `reducedMotion` **Default:** `"never"` `reducedMotion` lets you set a site-wide policy for handling reduced motion. It offers the following options: * `"user"`: Respect the user's device setting. * `"always"`: Enforce reduced motion (useful for debugging). * `"never"`: Don't respect reduced motion. When reduced motion is on, transform and layout animations will be disabled. Other animations, like `opacity` and `backgroundColor`, will persist. ### `nonce` If using a Content Security Policy with a `nonce` attribute, passing the same attribute through `MotionConfig` will allow any `style` blocks generated by Motion to adhere the the security policy. --- ## Page: https://motion.dev/docs/react-reorder # Reorder The `Reorder` components can be used to create drag-to-reorder lists, like reorderable tabs or todo items. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group axis\="y" values\={items} onReorder\={setItems}\> {items.map((item) \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) **Note:** `Reorder` is for simple drag-to-reorder implementations. It's exceptionally lightweight ontop of the base `motion` component but lacks some features like multirow, dragging between columns, or dragging within scrollable containers. For advanced use-cases we recommend something like DnD Kit. ## Usage Every reorderable list is wrapped in the `Reorder.Group` component. import { Reorder } from "motion/react" function List() { return ( <Reorder.Group\> </Reorder.Group\> ) } By default, this is rendered as a `<ul>`, but this can be changed with the `as` prop. <Reorder.Group as\="ol"\> `Reorder.Group` must be passed the array of values in your reorderable list via the `values` prop. Additionally, a `onReorder` event will fire with the latest calculated order. For items to reorder, this must update the `values` state. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> </Reorder.Group\> ) } To render each reorderable item, use `Reorder.Item`, passing it the value it represents via the `value` prop. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> {items.map(item \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) } Now, when items are dragged and reordered, `onReorder` will fire with a new order. ### Layout animations `Reorder.Item` components are already configured to perform layout animations, so if new items are added or removed to the reorderable list, surrounding items will animate to their new position automatically. ### Exit animations `AnimatePresence` can be used as normal to animate items as they enter/leave the React tree. <AnimatePresence\> {items.map(item \=> ( <Reorder.Item initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} key\={item} /> ))} </AnimatePresence\> ### Drag triggers By default, all of a `Reorder.Item` will be draggable. `useDragControls` can be used to define a different component to act as a drag trigger. import { Reorder, useDragControls } from "framer-motion" function Item({ value }) { const controls = useDragControls() return ( <Reorder.Item value\={value} dragListener\={false} dragControls\={controls} \> <div className\="reorder-handle" onPointerDown\={(e) \=> controls.start(e)} /> </Reorder.Item\> ) } ### Scrollable lists If `Reorder.Item` components are within a scrollable container, that container needs a `layoutScroll` prop so Framer Motion can correctly measure its scroll offset. <Reorder.Group axis\="y" onReorder\={setItems} layoutScroll style\={{ overflowY: "scroll" }} \> {items.map((item) \=> ( <Item key\={item} item\={item} /> ))} </Reorder.Group\> ### z-index `Reorder.Item` will automatically set a `z-index` style on the currently dragged item so it appears above the surrounding items. However, `z-index` only affects items with `position !== "static"`. So to enable this effect ensure the position of the `Reorder.Item` is set to `relative` or `absolute`. ## API ### `Reorder.Group` #### `as` **Default**: `"ul"` The underlying element for `Reorder.Group` to render as. <Reorder.Group as\="div"\></Reorder.Group\> #### `axis` **Default**: `"y"` The direction of reorder detection. **Note:** By default, all `Reorder.Item` components will visibly move only on this axis. To allow visual motion (but **not** reordering) on both axes, pass the `drag` prop to child `Reorder.Item` components. #### `values` The values array that will be reordered. Each item in this list must match a `value` passed to each `Reorder.Item`. #### `onReorder` A callback that will fire when items are detected to have reordered. The provided `newOrder` should be passed to a `values` state update function. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> ### `Reorder.Item` `Reorder.Item` components accept all `motion` component props in addition to the following: #### `as` **Default:** `"li"` The element for `Reorder.Item` to render as. #### `value` When `onReorder` is called, this is the value that will be passed through in the newly ordered array. The `Reorder` components can be used to create drag-to-reorder lists, like reorderable tabs or todo items. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group axis\="y" values\={items} onReorder\={setItems}\> {items.map((item) \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) **Note:** `Reorder` is for simple drag-to-reorder implementations. It's exceptionally lightweight ontop of the base `motion` component but lacks some features like multirow, dragging between columns, or dragging within scrollable containers. For advanced use-cases we recommend something like DnD Kit. ## Usage Every reorderable list is wrapped in the `Reorder.Group` component. import { Reorder } from "motion/react" function List() { return ( <Reorder.Group\> </Reorder.Group\> ) } By default, this is rendered as a `<ul>`, but this can be changed with the `as` prop. <Reorder.Group as\="ol"\> `Reorder.Group` must be passed the array of values in your reorderable list via the `values` prop. Additionally, a `onReorder` event will fire with the latest calculated order. For items to reorder, this must update the `values` state. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> </Reorder.Group\> ) } To render each reorderable item, use `Reorder.Item`, passing it the value it represents via the `value` prop. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> {items.map(item \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) } Now, when items are dragged and reordered, `onReorder` will fire with a new order. ### Layout animations `Reorder.Item` components are already configured to perform layout animations, so if new items are added or removed to the reorderable list, surrounding items will animate to their new position automatically. ### Exit animations `AnimatePresence` can be used as normal to animate items as they enter/leave the React tree. <AnimatePresence\> {items.map(item \=> ( <Reorder.Item initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} key\={item} /> ))} </AnimatePresence\> ### Drag triggers By default, all of a `Reorder.Item` will be draggable. `useDragControls` can be used to define a different component to act as a drag trigger. import { Reorder, useDragControls } from "framer-motion" function Item({ value }) { const controls = useDragControls() return ( <Reorder.Item value\={value} dragListener\={false} dragControls\={controls} \> <div className\="reorder-handle" onPointerDown\={(e) \=> controls.start(e)} /> </Reorder.Item\> ) } ### Scrollable lists If `Reorder.Item` components are within a scrollable container, that container needs a `layoutScroll` prop so Framer Motion can correctly measure its scroll offset. <Reorder.Group axis\="y" onReorder\={setItems} layoutScroll style\={{ overflowY: "scroll" }} \> {items.map((item) \=> ( <Item key\={item} item\={item} /> ))} </Reorder.Group\> ### z-index `Reorder.Item` will automatically set a `z-index` style on the currently dragged item so it appears above the surrounding items. However, `z-index` only affects items with `position !== "static"`. So to enable this effect ensure the position of the `Reorder.Item` is set to `relative` or `absolute`. ## API ### `Reorder.Group` #### `as` **Default**: `"ul"` The underlying element for `Reorder.Group` to render as. <Reorder.Group as\="div"\></Reorder.Group\> #### `axis` **Default**: `"y"` The direction of reorder detection. **Note:** By default, all `Reorder.Item` components will visibly move only on this axis. To allow visual motion (but **not** reordering) on both axes, pass the `drag` prop to child `Reorder.Item` components. #### `values` The values array that will be reordered. Each item in this list must match a `value` passed to each `Reorder.Item`. #### `onReorder` A callback that will fire when items are detected to have reordered. The provided `newOrder` should be passed to a `values` state update function. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> ### `Reorder.Item` `Reorder.Item` components accept all `motion` component props in addition to the following: #### `as` **Default:** `"li"` The element for `Reorder.Item` to render as. #### `value` When `onReorder` is called, this is the value that will be passed through in the newly ordered array. The `Reorder` components can be used to create drag-to-reorder lists, like reorderable tabs or todo items. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group axis\="y" values\={items} onReorder\={setItems}\> {items.map((item) \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) **Note:** `Reorder` is for simple drag-to-reorder implementations. It's exceptionally lightweight ontop of the base `motion` component but lacks some features like multirow, dragging between columns, or dragging within scrollable containers. For advanced use-cases we recommend something like DnD Kit. ## Usage Every reorderable list is wrapped in the `Reorder.Group` component. import { Reorder } from "motion/react" function List() { return ( <Reorder.Group\> </Reorder.Group\> ) } By default, this is rendered as a `<ul>`, but this can be changed with the `as` prop. <Reorder.Group as\="ol"\> `Reorder.Group` must be passed the array of values in your reorderable list via the `values` prop. Additionally, a `onReorder` event will fire with the latest calculated order. For items to reorder, this must update the `values` state. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> </Reorder.Group\> ) } To render each reorderable item, use `Reorder.Item`, passing it the value it represents via the `value` prop. import { Reorder } from "framer-motion" function List() { const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> {items.map(item \=> ( <Reorder.Item key\={item} value\={item}\> {item} </Reorder.Item\> ))} </Reorder.Group\> ) } Now, when items are dragged and reordered, `onReorder` will fire with a new order. ### Layout animations `Reorder.Item` components are already configured to perform layout animations, so if new items are added or removed to the reorderable list, surrounding items will animate to their new position automatically. ### Exit animations `AnimatePresence` can be used as normal to animate items as they enter/leave the React tree. <AnimatePresence\> {items.map(item \=> ( <Reorder.Item initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} exit\={{ opacity: 0 }} key\={item} /> ))} </AnimatePresence\> ### Drag triggers By default, all of a `Reorder.Item` will be draggable. `useDragControls` can be used to define a different component to act as a drag trigger. import { Reorder, useDragControls } from "framer-motion" function Item({ value }) { const controls = useDragControls() return ( <Reorder.Item value\={value} dragListener\={false} dragControls\={controls} \> <div className\="reorder-handle" onPointerDown\={(e) \=> controls.start(e)} /> </Reorder.Item\> ) } ### Scrollable lists If `Reorder.Item` components are within a scrollable container, that container needs a `layoutScroll` prop so Framer Motion can correctly measure its scroll offset. <Reorder.Group axis\="y" onReorder\={setItems} layoutScroll style\={{ overflowY: "scroll" }} \> {items.map((item) \=> ( <Item key\={item} item\={item} /> ))} </Reorder.Group\> ### z-index `Reorder.Item` will automatically set a `z-index` style on the currently dragged item so it appears above the surrounding items. However, `z-index` only affects items with `position !== "static"`. So to enable this effect ensure the position of the `Reorder.Item` is set to `relative` or `absolute`. ## API ### `Reorder.Group` #### `as` **Default**: `"ul"` The underlying element for `Reorder.Group` to render as. <Reorder.Group as\="div"\></Reorder.Group\> #### `axis` **Default**: `"y"` The direction of reorder detection. **Note:** By default, all `Reorder.Item` components will visibly move only on this axis. To allow visual motion (but **not** reordering) on both axes, pass the `drag` prop to child `Reorder.Item` components. #### `values` The values array that will be reordered. Each item in this list must match a `value` passed to each `Reorder.Item`. #### `onReorder` A callback that will fire when items are detected to have reordered. The provided `newOrder` should be passed to a `values` state update function. const \[items, setItems\] = useState(\[0, 1, 2, 3\]) return ( <Reorder.Group values\={items} onReorder\={setItems}\> ### `Reorder.Item` `Reorder.Item` components accept all `motion` component props in addition to the following: #### `as` **Default:** `"li"` The element for `Reorder.Item` to render as. #### `value` When `onReorder` is called, this is the value that will be passed through in the newly ordered array. --- ## Page: https://motion.dev/docs/react-motion-value # Motion values overview Motion values track the state and velocity of animated values. They are composable, signal-like values that are performant because Motion can render them with its optimised DOM renderer. Usually, these are created automatically by `motion` components. But for advanced use cases, it's possible to create them manually. import { motion, useMotionValue } from "motion/react" export function MyComponent() { const x = useMotionValue(0) return <motion.div style\={{ x }} /> } By manually creating motion values you can: * Set and get their state. * Pass to multiple components to synchronise motion across them. * Chain `MotionValue`s via the `useTransform` hook. * Update visual properties without triggering React's render cycle. * Subscribe to updates. const x = useMotionValue(0) const opacity = useTransform( x, \[\-200, 0, 200\], \[0, 1, 0\] ) // Will change opacity as element is dragged left/right return <motion.div drag\="x" style\={{ x, opacity }} /> ## Usage Motion values can be created with the `useMotionValue` hook. The string or number passed to `useMotionValue` will act as its initial state. import { useMotionValue } from "motion/react" const x = useMotionValue(0) Motion values can be passed to a `motion` component via `style`: <motion.li style\={{ x }} /> Or for SVG attributes, via the attribute prop itself: <motion.circle cx\={cx} /> It's possible to pass the same motion value to multiple components. Motion values can be updated with the `set` method. x.set(100) Changes to the motion value will update the DOM **without triggering a React re-render**. Motion values can be updated multiple times but renders will be batched to the next animation frame. A motion value can hold any string or number. We can read it with the `get` method. x.get() // 100 Motion values containing a 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. const xVelocity = x.getVelocity() For strings and colors, `getVelocity` will always return `0`. ### Events Listeners can be added to motion values via the `on` method or the `useMotionValueEvent` hook. useMotionValueEvent(x, "change", (latest) \=> console.log(latest)) Available events are `"change"`, `"animationStart"`, `"animationComplete"` `"animationCancel"`. ### Composition Beyond `useMotionValue`, Motion provides a number of hooks for creating and composing motion values, like `useSpring` and `useTransform`. For example, with `useTransform` we can take the latest state of one or more motion values and create a new motion value with the result. const y = useTransform(() \=> x.get() \* 2) `useSpring` can make a motion value that's attached to another via a spring. const dragX = useMotionValue(0) const dragY = useMotionValue(0) const x = useSpring(dragX) const y = useSpring(dragY) These motion values can then go on to be passed to `motion` components, or composed with more hooks like `useVelocity`. ## API ### `get()` Returns the latest state of the motion value. ### `getVelocity()` Returns the latest velocity of the motion value. Returns `0` if the value is non-numerical. ### `set()` Sets the motion value to a new state. x.set("#f00") ### `jump()` Jumps the motion value to a new state in a way that breaks continuity from previous values: * Resets `velocity` to `0`. * Ends active animations. * Ignores attached effects (for instance `useSpring`'s spring). const x = useSpring(0) x.jump(10) x.getVelocity() // 0 ### `isAnimating()` Returns `true` if the value is currently animating. ### `stop()` Stop the active animation. ### `on()` Subscribe to motion value events. Available events are: * `change` * `animationStart` * `animationCancel` * `animationComplete` It returns a function that, when called, will unsubscribe the listener. const unsubscribe = x.on("change", latest \=> console.log(latest)) When calling `on` inside a React component, it should be wrapped with a `useEffect` hook, or instead use the `useMotionValueEvent` hook. ### `destroy()` Destroy and clean up subscribers to this motion value. This is normally handled automatically, so this method is only necessary if you've manually created a motion value outside the React render cycle using the vanilla `motionValue` hook. Motion values track the state and velocity of animated values. They are composable, signal-like values that are performant because Motion can render them with its optimised DOM renderer. Usually, these are created automatically by `motion` components. But for advanced use cases, it's possible to create them manually. import { motion, useMotionValue } from "motion/react" export function MyComponent() { const x = useMotionValue(0) return <motion.div style\={{ x }} /> } By manually creating motion values you can: * Set and get their state. * Pass to multiple components to synchronise motion across them. * Chain `MotionValue`s via the `useTransform` hook. * Update visual properties without triggering React's render cycle. * Subscribe to updates. const x = useMotionValue(0) const opacity = useTransform( x, \[\-200, 0, 200\], \[0, 1, 0\] ) // Will change opacity as element is dragged left/right return <motion.div drag\="x" style\={{ x, opacity }} /> ## Usage Motion values can be created with the `useMotionValue` hook. The string or number passed to `useMotionValue` will act as its initial state. import { useMotionValue } from "motion/react" const x = useMotionValue(0) Motion values can be passed to a `motion` component via `style`: <motion.li style\={{ x }} /> Or for SVG attributes, via the attribute prop itself: <motion.circle cx\={cx} /> It's possible to pass the same motion value to multiple components. Motion values can be updated with the `set` method. x.set(100) Changes to the motion value will update the DOM **without triggering a React re-render**. Motion values can be updated multiple times but renders will be batched to the next animation frame. A motion value can hold any string or number. We can read it with the `get` method. x.get() // 100 Motion values containing a 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. const xVelocity = x.getVelocity() For strings and colors, `getVelocity` will always return `0`. ### Events Listeners can be added to motion values via the `on` method or the `useMotionValueEvent` hook. useMotionValueEvent(x, "change", (latest) \=> console.log(latest)) Available events are `"change"`, `"animationStart"`, `"animationComplete"` `"animationCancel"`. ### Composition Beyond `useMotionValue`, Motion provides a number of hooks for creating and composing motion values, like `useSpring` and `useTransform`. For example, with `useTransform` we can take the latest state of one or more motion values and create a new motion value with the result. const y = useTransform(() \=> x.get() \* 2) `useSpring` can make a motion value that's attached to another via a spring. const dragX = useMotionValue(0) const dragY = useMotionValue(0) const x = useSpring(dragX) const y = useSpring(dragY) These motion values can then go on to be passed to `motion` components, or composed with more hooks like `useVelocity`. ## API ### `get()` Returns the latest state of the motion value. ### `getVelocity()` Returns the latest velocity of the motion value. Returns `0` if the value is non-numerical. ### `set()` Sets the motion value to a new state. x.set("#f00") ### `jump()` Jumps the motion value to a new state in a way that breaks continuity from previous values: * Resets `velocity` to `0`. * Ends active animations. * Ignores attached effects (for instance `useSpring`'s spring). const x = useSpring(0) x.jump(10) x.getVelocity() // 0 ### `isAnimating()` Returns `true` if the value is currently animating. ### `stop()` Stop the active animation. ### `on()` Subscribe to motion value events. Available events are: * `change` * `animationStart` * `animationCancel` * `animationComplete` It returns a function that, when called, will unsubscribe the listener. const unsubscribe = x.on("change", latest \=> console.log(latest)) When calling `on` inside a React component, it should be wrapped with a `useEffect` hook, or instead use the `useMotionValueEvent` hook. ### `destroy()` Destroy and clean up subscribers to this motion value. This is normally handled automatically, so this method is only necessary if you've manually created a motion value outside the React render cycle using the vanilla `motionValue` hook. Motion values track the state and velocity of animated values. They are composable, signal-like values that are performant because Motion can render them with its optimised DOM renderer. Usually, these are created automatically by `motion` components. But for advanced use cases, it's possible to create them manually. import { motion, useMotionValue } from "motion/react" export function MyComponent() { const x = useMotionValue(0) return <motion.div style\={{ x }} /> } By manually creating motion values you can: * Set and get their state. * Pass to multiple components to synchronise motion across them. * Chain `MotionValue`s via the `useTransform` hook. * Update visual properties without triggering React's render cycle. * Subscribe to updates. const x = useMotionValue(0) const opacity = useTransform( x, \[\-200, 0, 200\], \[0, 1, 0\] ) // Will change opacity as element is dragged left/right return <motion.div drag\="x" style\={{ x, opacity }} /> ## Usage Motion values can be created with the `useMotionValue` hook. The string or number passed to `useMotionValue` will act as its initial state. import { useMotionValue } from "motion/react" const x = useMotionValue(0) Motion values can be passed to a `motion` component via `style`: <motion.li style\={{ x }} /> Or for SVG attributes, via the attribute prop itself: <motion.circle cx\={cx} /> It's possible to pass the same motion value to multiple components. Motion values can be updated with the `set` method. x.set(100) Changes to the motion value will update the DOM **without triggering a React re-render**. Motion values can be updated multiple times but renders will be batched to the next animation frame. A motion value can hold any string or number. We can read it with the `get` method. x.get() // 100 Motion values containing a 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. const xVelocity = x.getVelocity() For strings and colors, `getVelocity` will always return `0`. ### Events Listeners can be added to motion values via the `on` method or the `useMotionValueEvent` hook. useMotionValueEvent(x, "change", (latest) \=> console.log(latest)) Available events are `"change"`, `"animationStart"`, `"animationComplete"` `"animationCancel"`. ### Composition Beyond `useMotionValue`, Motion provides a number of hooks for creating and composing motion values, like `useSpring` and `useTransform`. For example, with `useTransform` we can take the latest state of one or more motion values and create a new motion value with the result. const y = useTransform(() \=> x.get() \* 2) `useSpring` can make a motion value that's attached to another via a spring. const dragX = useMotionValue(0) const dragY = useMotionValue(0) const x = useSpring(dragX) const y = useSpring(dragY) These motion values can then go on to be passed to `motion` components, or composed with more hooks like `useVelocity`. ## API ### `get()` Returns the latest state of the motion value. ### `getVelocity()` Returns the latest velocity of the motion value. Returns `0` if the value is non-numerical. ### `set()` Sets the motion value to a new state. x.set("#f00") ### `jump()` Jumps the motion value to a new state in a way that breaks continuity from previous values: * Resets `velocity` to `0`. * Ends active animations. * Ignores attached effects (for instance `useSpring`'s spring). const x = useSpring(0) x.jump(10) x.getVelocity() // 0 ### `isAnimating()` Returns `true` if the value is currently animating. ### `stop()` Stop the active animation. ### `on()` Subscribe to motion value events. Available events are: * `change` * `animationStart` * `animationCancel` * `animationComplete` It returns a function that, when called, will unsubscribe the listener. const unsubscribe = x.on("change", latest \=> console.log(latest)) When calling `on` inside a React component, it should be wrapped with a `useEffect` hook, or instead use the `useMotionValueEvent` hook. ### `destroy()` Destroy and clean up subscribers to this motion value. This is normally handled automatically, so this method is only necessary if you've manually created a motion value outside the React render cycle using the vanilla `motionValue` hook. --- ## Page: https://motion.dev/docs/react-use-motion-template # useMotionTemplate `useMotionTemplate` creates a new motion value from a string template containing other motion values. const x = useMotionValue(100) const transform = useMotionTemplate\`transform(${x}px)\` Whenever a motion value within the string template updates, the returned motion value will update with the latest value. ## Usage Import from Motion: import { useMotionTemplate } from "motion/react" `useMotionTemplate` is a "tagged template", so rather than being called like a normal function, it's called as a string template: useMotionValue\`\` This string template can accept both text and other motion values: const blur = useMotionValue(10) const saturate = useMotionValue(50) const filter = useMotionTemplate\`blur(${10}px) saturate(${saturate}%)\` return <motion.div style\={{ filter }} /> The latest value of the returned motion value will be the string template with each provided motion value replaced with its latest value. const shadowX = useSpring(0) const shadowY = useMotionValue(0) const filter = useMotionTemplate\`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))\` return <motion.div style\={{ filter }} /> `useMotionTemplate` creates a new motion value from a string template containing other motion values. const x = useMotionValue(100) const transform = useMotionTemplate\`transform(${x}px)\` Whenever a motion value within the string template updates, the returned motion value will update with the latest value. ## Usage Import from Motion: import { useMotionTemplate } from "motion/react" `useMotionTemplate` is a "tagged template", so rather than being called like a normal function, it's called as a string template: useMotionValue\`\` This string template can accept both text and other motion values: const blur = useMotionValue(10) const saturate = useMotionValue(50) const filter = useMotionTemplate\`blur(${10}px) saturate(${saturate}%)\` return <motion.div style\={{ filter }} /> The latest value of the returned motion value will be the string template with each provided motion value replaced with its latest value. const shadowX = useSpring(0) const shadowY = useMotionValue(0) const filter = useMotionTemplate\`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))\` return <motion.div style\={{ filter }} /> `useMotionTemplate` creates a new motion value from a string template containing other motion values. const x = useMotionValue(100) const transform = useMotionTemplate\`transform(${x}px)\` Whenever a motion value within the string template updates, the returned motion value will update with the latest value. ## Usage Import from Motion: import { useMotionTemplate } from "motion/react" `useMotionTemplate` is a "tagged template", so rather than being called like a normal function, it's called as a string template: useMotionValue\`\` This string template can accept both text and other motion values: const blur = useMotionValue(10) const saturate = useMotionValue(50) const filter = useMotionTemplate\`blur(${10}px) saturate(${saturate}%)\` return <motion.div style\={{ filter }} /> The latest value of the returned motion value will be the string template with each provided motion value replaced with its latest value. const shadowX = useSpring(0) const shadowY = useMotionValue(0) const filter = useMotionTemplate\`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))\` return <motion.div style\={{ filter }} /> --- ## Page: https://motion.dev/docs/react-use-motion-value-event # useMotionValueEvent `useMotionValueEvent` manages a motion value event handler throughout the lifecycle of a React component. function Component() { const x = useMotionValue(0) useMotionValueEvent(x, "animationStart", () \=> { console.log("animation started on x") }) useMotionValueEvent(x, "change", (latest) \=> { console.log("x changed to", latest) }) return <motion.div style\={{ x }} /> } When the component is unmounted, event handlers will be safely cleaned up. ## Usage Import from Motion: import { useMotionValueEvent } from "motion/react" To add an event listener to a motion value, provide the value, event name and callback: const color = useMotionValue("#00f") useMotionValueEvent(color, "change", (latest) \=> { console.log(latest) }) Available events are: * `change` * `animationStart` * `animationComplete` * `animationCancel` `"change"` events are provided the latest value of the motion value. ### Advanced `useMotionValueEvent` is a helper function for a motion value's `on` method. With `on`, you can start listening to events whenever you like, for instance within an event handler. But remember to also unsubscribe when the component unmounts. useEffect(() \=> { const doSomething = () \=> {} const unsubX = x.on("change", doSomething) const unsubY = y.on("change", doSomething) return () \=> { unsubX() unsubY() } }, \[x, y\]) `useMotionValueEvent` manages a motion value event handler throughout the lifecycle of a React component. function Component() { const x = useMotionValue(0) useMotionValueEvent(x, "animationStart", () \=> { console.log("animation started on x") }) useMotionValueEvent(x, "change", (latest) \=> { console.log("x changed to", latest) }) return <motion.div style\={{ x }} /> } When the component is unmounted, event handlers will be safely cleaned up. ## Usage Import from Motion: import { useMotionValueEvent } from "motion/react" To add an event listener to a motion value, provide the value, event name and callback: const color = useMotionValue("#00f") useMotionValueEvent(color, "change", (latest) \=> { console.log(latest) }) Available events are: * `change` * `animationStart` * `animationComplete` * `animationCancel` `"change"` events are provided the latest value of the motion value. ### Advanced `useMotionValueEvent` is a helper function for a motion value's `on` method. With `on`, you can start listening to events whenever you like, for instance within an event handler. But remember to also unsubscribe when the component unmounts. useEffect(() \=> { const doSomething = () \=> {} const unsubX = x.on("change", doSomething) const unsubY = y.on("change", doSomething) return () \=> { unsubX() unsubY() } }, \[x, y\]) `useMotionValueEvent` manages a motion value event handler throughout the lifecycle of a React component. function Component() { const x = useMotionValue(0) useMotionValueEvent(x, "animationStart", () \=> { console.log("animation started on x") }) useMotionValueEvent(x, "change", (latest) \=> { console.log("x changed to", latest) }) return <motion.div style\={{ x }} /> } When the component is unmounted, event handlers will be safely cleaned up. ## Usage Import from Motion: import { useMotionValueEvent } from "motion/react" To add an event listener to a motion value, provide the value, event name and callback: const color = useMotionValue("#00f") useMotionValueEvent(color, "change", (latest) \=> { console.log(latest) }) Available events are: * `change` * `animationStart` * `animationComplete` * `animationCancel` `"change"` events are provided the latest value of the motion value. ### Advanced `useMotionValueEvent` is a helper function for a motion value's `on` method. With `on`, you can start listening to events whenever you like, for instance within an event handler. But remember to also unsubscribe when the component unmounts. useEffect(() \=> { const doSomething = () \=> {} const unsubX = x.on("change", doSomething) const unsubY = y.on("change", doSomething) return () \=> { unsubX() unsubY() } }, \[x, y\]) --- ## Page: https://motion.dev/docs/react-use-scroll # useScroll `useScroll` is used to create scroll-linked animations, like progress indicators and parallax effects. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> ## Usage Import `useScroll` from Motion: import { useScroll } from "motion/react" `useScroll` returns four motion values: * `scrollX`/`Y`: The absolute scroll position, in pixels. * `scrollXProgress`/`YProgress`: The scroll position between the defined offsets, as a value between `0` and `1`. ### Page scroll By default, useScroll tracks the page scroll. const { scrollY } = useScroll() useMotionValueEvent(scrollY, "change", (latest) \=> { console.log("Page scroll: ", latest) }) For example, we could show a page scroll indicator by passing `scrollYProgress` straight to the `scaleX` style of a progress bar. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> As `useScroll` returns motion values, we can compose this scroll info with other motion value hooks like `useTransform` and `useSpring`: const { scrollYProgress } = useScroll() const scaleX = useSpring(scrollYProgress) return <motion.div style\={{ scaleX }} /> > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > > ~ Sam Selikoff, Motion for React Recipes ### Element scroll To track the scroll position of a scrollable element we can pass the element's `ref` to `useScroll`'s `container` option: const carouselRef = useRef(null) const { scrollX } = useScroll({ container: carouselRef }) return ( <div ref\={carouselRef} style\={{ overflow: "scroll" }}\> {children} </div\> ) ### Element position We can track the progress of an element as it moves within a container by passing its `ref` to the `target` option. const ref = useRef(null) const { scrollYProgress } = useScroll({ target: ref, offset: \["start end", "end end"\] }) return <div ref\={ref}\> In this example, each item has its own progress indicator. ### Scroll offsets With the `offset` option we can define which parts of the element we want to track with the viewport, for instance track elements as they enter in from the bottom, leave at the top, or travel throughout the whole viewport. ## API `useScroll` accepts the following options. ### `container` **Default**: Browser window The scrollable container to track the scroll position of. By default, this is the window viewport. But it can be any scrollable element. ### `target` By default, this is the scrollable area of the container. It can additionally be set as another element, to track its progress within the viewport. ### `axis` **Default:** `"y"` The scroll axis to apply `offset`. ### `offset` **Default:** `["start start", "end end"]` `offset` describes intersections, points where the `target` and `container` meet. For example, the intersection `"start end"` means when the **start of the target** on the tracked axis meets the **end of the container.** So if the target is an element, the container is the window, and we're tracking the vertical axis then `"start end"` is where the **top of the element** meets **the bottom of the viewport**. #### Accepted intersections Both target and container points can be defined as: * **Number:** A value where `0` represents the start of the axis and `1` represents the end. So to define the top of the target with the middle of the container you could define `"0 0.5"`. Values outside this range are permitted. * **Names:** `"start"`, `"center"` and `"end"` can be used as clear shortcuts for `0`, `0.5` and `1` respectively. * **Pixels:** Pixel values like `"100px"`, `"-50px"` will be defined as that number of pixels from the start of the target/container. * **Percent:** Same as raw numbers but expressed as `"0%"` to `"100%"`. * **Viewport:** `"vh"` and `"vw"` units are accepted. ## Examples ### React Three Fiber ### Scroll velocity `useScroll` is used to create scroll-linked animations, like progress indicators and parallax effects. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> ## Usage Import `useScroll` from Motion: import { useScroll } from "motion/react" `useScroll` returns four motion values: * `scrollX`/`Y`: The absolute scroll position, in pixels. * `scrollXProgress`/`YProgress`: The scroll position between the defined offsets, as a value between `0` and `1`. ### Page scroll By default, useScroll tracks the page scroll. const { scrollY } = useScroll() useMotionValueEvent(scrollY, "change", (latest) \=> { console.log("Page scroll: ", latest) }) For example, we could show a page scroll indicator by passing `scrollYProgress` straight to the `scaleX` style of a progress bar. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> As `useScroll` returns motion values, we can compose this scroll info with other motion value hooks like `useTransform` and `useSpring`: const { scrollYProgress } = useScroll() const scaleX = useSpring(scrollYProgress) return <motion.div style\={{ scaleX }} /> > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > > ~ Sam Selikoff, Motion for React Recipes ### Element scroll To track the scroll position of a scrollable element we can pass the element's `ref` to `useScroll`'s `container` option: const carouselRef = useRef(null) const { scrollX } = useScroll({ container: carouselRef }) return ( <div ref\={carouselRef} style\={{ overflow: "scroll" }}\> {children} </div\> ) ### Element position We can track the progress of an element as it moves within a container by passing its `ref` to the `target` option. const ref = useRef(null) const { scrollYProgress } = useScroll({ target: ref, offset: \["start end", "end end"\] }) return <div ref\={ref}\> In this example, each item has its own progress indicator. ### Scroll offsets With the `offset` option we can define which parts of the element we want to track with the viewport, for instance track elements as they enter in from the bottom, leave at the top, or travel throughout the whole viewport. ## API `useScroll` accepts the following options. ### `container` **Default**: Browser window The scrollable container to track the scroll position of. By default, this is the window viewport. But it can be any scrollable element. ### `target` By default, this is the scrollable area of the container. It can additionally be set as another element, to track its progress within the viewport. ### `axis` **Default:** `"y"` The scroll axis to apply `offset`. ### `offset` **Default:** `["start start", "end end"]` `offset` describes intersections, points where the `target` and `container` meet. For example, the intersection `"start end"` means when the **start of the target** on the tracked axis meets the **end of the container.** So if the target is an element, the container is the window, and we're tracking the vertical axis then `"start end"` is where the **top of the element** meets **the bottom of the viewport**. #### Accepted intersections Both target and container points can be defined as: * **Number:** A value where `0` represents the start of the axis and `1` represents the end. So to define the top of the target with the middle of the container you could define `"0 0.5"`. Values outside this range are permitted. * **Names:** `"start"`, `"center"` and `"end"` can be used as clear shortcuts for `0`, `0.5` and `1` respectively. * **Pixels:** Pixel values like `"100px"`, `"-50px"` will be defined as that number of pixels from the start of the target/container. * **Percent:** Same as raw numbers but expressed as `"0%"` to `"100%"`. * **Viewport:** `"vh"` and `"vw"` units are accepted. ## Examples ### React Three Fiber ### Scroll velocity `useScroll` is used to create scroll-linked animations, like progress indicators and parallax effects. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> ## Usage Import `useScroll` from Motion: import { useScroll } from "motion/react" `useScroll` returns four motion values: * `scrollX`/`Y`: The absolute scroll position, in pixels. * `scrollXProgress`/`YProgress`: The scroll position between the defined offsets, as a value between `0` and `1`. ### Page scroll By default, useScroll tracks the page scroll. const { scrollY } = useScroll() useMotionValueEvent(scrollY, "change", (latest) \=> { console.log("Page scroll: ", latest) }) For example, we could show a page scroll indicator by passing `scrollYProgress` straight to the `scaleX` style of a progress bar. const { scrollYProgress } = useScroll() return <motion.div style\={{ scaleX: scrollYProgress }} /> As `useScroll` returns motion values, we can compose this scroll info with other motion value hooks like `useTransform` and `useSpring`: const { scrollYProgress } = useScroll() const scaleX = useSpring(scrollYProgress) return <motion.div style\={{ scaleX }} /> > Since `scrollY` is a `MotionValue`, there's a neat trick you can use to tell when the user's scroll direction changes: > > const { scrollY } = useScroll() > const \[scrollDirection, setScrollDirection\] = useState("down") > > useMotionValueEvent(scrollY, "change", (current) \=> { > const diff = current - scrollY.getPrevious() > setScrollDirection(diff > 0 ? "down" : "up") > }) > > Perfect for triggering a sticky header animation! > > ~ Sam Selikoff, Motion for React Recipes ### Element scroll To track the scroll position of a scrollable element we can pass the element's `ref` to `useScroll`'s `container` option: const carouselRef = useRef(null) const { scrollX } = useScroll({ container: carouselRef }) return ( <div ref\={carouselRef} style\={{ overflow: "scroll" }}\> {children} </div\> ) ### Element position We can track the progress of an element as it moves within a container by passing its `ref` to the `target` option. const ref = useRef(null) const { scrollYProgress } = useScroll({ target: ref, offset: \["start end", "end end"\] }) return <div ref\={ref}\> In this example, each item has its own progress indicator. ### Scroll offsets With the `offset` option we can define which parts of the element we want to track with the viewport, for instance track elements as they enter in from the bottom, leave at the top, or travel throughout the whole viewport. ## API `useScroll` accepts the following options. ### `container` **Default**: Browser window The scrollable container to track the scroll position of. By default, this is the window viewport. But it can be any scrollable element. ### `target` By default, this is the scrollable area of the container. It can additionally be set as another element, to track its progress within the viewport. ### `axis` **Default:** `"y"` The scroll axis to apply `offset`. ### `offset` **Default:** `["start start", "end end"]` `offset` describes intersections, points where the `target` and `container` meet. For example, the intersection `"start end"` means when the **start of the target** on the tracked axis meets the **end of the container.** So if the target is an element, the container is the window, and we're tracking the vertical axis then `"start end"` is where the **top of the element** meets **the bottom of the viewport**. #### Accepted intersections Both target and container points can be defined as: * **Number:** A value where `0` represents the start of the axis and `1` represents the end. So to define the top of the target with the middle of the container you could define `"0 0.5"`. Values outside this range are permitted. * **Names:** `"start"`, `"center"` and `"end"` can be used as clear shortcuts for `0`, `0.5` and `1` respectively. * **Pixels:** Pixel values like `"100px"`, `"-50px"` will be defined as that number of pixels from the start of the target/container. * **Percent:** Same as raw numbers but expressed as `"0%"` to `"100%"`. * **Viewport:** `"vh"` and `"vw"` units are accepted. ## Examples ### React Three Fiber ### Scroll velocity --- ## Page: https://motion.dev/docs/react-use-spring # useSpring `useSpring` creates a motion value that will animate to its latest target with a spring animation. The target can either be set manually via `.set`, or automatically by passing in another motion value. ## Usage Import `useSpring` from Motion: import { useSpring } from "motion/react" ### Direct control `useSpring` can be created with a number, or a unit-type (`px`, `%` etc) string: const x = useSpring(0) const y = useSpring("100vh") Now, whenever this motion value is updated via `set()`, the value will animate to its new target with the defined spring. x.set(100) y.set("50vh") It's also possible to update this value immediately, without a spring, with the `jump()` method. x.jump(50) y.jump("0vh") ### Track another motion value Its also possible to automatically spring towards the latest value of another motion value: const x = useMotionValue(0) const y = useSpring(x) This source motion value must also be a number, or unit-type string. ### Transition The type of `spring` can be defined with the usual spring transition option. useSpring(0, { stiffness: 300 }) `useSpring` creates a motion value that will animate to its latest target with a spring animation. The target can either be set manually via `.set`, or automatically by passing in another motion value. ## Usage Import `useSpring` from Motion: import { useSpring } from "motion/react" ### Direct control `useSpring` can be created with a number, or a unit-type (`px`, `%` etc) string: const x = useSpring(0) const y = useSpring("100vh") Now, whenever this motion value is updated via `set()`, the value will animate to its new target with the defined spring. x.set(100) y.set("50vh") It's also possible to update this value immediately, without a spring, with the `jump()` method. x.jump(50) y.jump("0vh") ### Track another motion value Its also possible to automatically spring towards the latest value of another motion value: const x = useMotionValue(0) const y = useSpring(x) This source motion value must also be a number, or unit-type string. ### Transition The type of `spring` can be defined with the usual spring transition option. useSpring(0, { stiffness: 300 }) `useSpring` creates a motion value that will animate to its latest target with a spring animation. The target can either be set manually via `.set`, or automatically by passing in another motion value. ## Usage Import `useSpring` from Motion: import { useSpring } from "motion/react" ### Direct control `useSpring` can be created with a number, or a unit-type (`px`, `%` etc) string: const x = useSpring(0) const y = useSpring("100vh") Now, whenever this motion value is updated via `set()`, the value will animate to its new target with the defined spring. x.set(100) y.set("50vh") It's also possible to update this value immediately, without a spring, with the `jump()` method. x.jump(50) y.jump("0vh") ### Track another motion value Its also possible to automatically spring towards the latest value of another motion value: const x = useMotionValue(0) const y = useSpring(x) This source motion value must also be a number, or unit-type string. ### Transition The type of `spring` can be defined with the usual spring transition option. useSpring(0, { stiffness: 300 }) --- ## Page: https://motion.dev/docs/react-use-time # useTime `useTime` returns a motion value that updates once per frame with the duration, in milliseconds, since it was first created. This is especially useful in generating perpetual animations. const time = useTime(); const rotate = useTransform(time, \[0, 4000\], \[0, 360\], { clamp: false }); return <motion.div style\={{ rotate }} /> ## Usage Import from Motion: import { useTime } from "motion/react" When called, `useTime` will create a new motion value. This value will update every frame with the time since its creation. You can use this either directly or by composing with other motion value hooks. const time = useTime() const rotate = useTransform( time, \[0, 4000\], // For every 4 seconds... \[0, 360\], // ...rotate 360deg { clamp: false } ) `useTime` returns a motion value that updates once per frame with the duration, in milliseconds, since it was first created. This is especially useful in generating perpetual animations. const time = useTime(); const rotate = useTransform(time, \[0, 4000\], \[0, 360\], { clamp: false }); return <motion.div style\={{ rotate }} /> ## Usage Import from Motion: import { useTime } from "motion/react" When called, `useTime` will create a new motion value. This value will update every frame with the time since its creation. You can use this either directly or by composing with other motion value hooks. const time = useTime() const rotate = useTransform( time, \[0, 4000\], // For every 4 seconds... \[0, 360\], // ...rotate 360deg { clamp: false } ) `useTime` returns a motion value that updates once per frame with the duration, in milliseconds, since it was first created. This is especially useful in generating perpetual animations. const time = useTime(); const rotate = useTransform(time, \[0, 4000\], \[0, 360\], { clamp: false }); return <motion.div style\={{ rotate }} /> ## Usage Import from Motion: import { useTime } from "motion/react" When called, `useTime` will create a new motion value. This value will update every frame with the time since its creation. You can use this either directly or by composing with other motion value hooks. const time = useTime() const rotate = useTransform( time, \[0, 4000\], // For every 4 seconds... \[0, 360\], // ...rotate 360deg { clamp: false } ) --- ## Page: https://motion.dev/docs/react-use-transform # useTransform `useTransform` creates a new motion value that transforms the output of one or more motion values. const x = useMotionValue(1) const y = useMotionValue(1) const z = useTransform(() \=> x.get() + y.get()) // z.get() === 2 ## Usage Import from Motion: import { useTransform } from "motion/react" `useTransform` can be used in two ways: with a transform function and via value maps: // Transform function useTransform(() \=> x.get() \* 2) // Value mapping useTransform(x, \[0, 100\], \["#f00", "00f"\]) ### Transform function A transform function is a normal function that returns a value. useTransform(() \=> x.get() \* 2) Any motion values read in this function via the `get()` method will be automatically subscribed to. When these motion values change, the function will be run again on the next animation frame to calculate a new value. const distance = 100 const time = useTime() const y = useTransform(() \=> Math.sin(time.get() / 1000) \* distance) ### Value mapping `useTransform` can also map a single motion value from one range of values to another. To illustrate, look at this `x` motion value: const x = useMotionValue(0) We can use `useTransform` to create a new motion value called `opacity`. const opacity = useTransform(x, input, output) By defining an `input` range and an `output` range, we can define relationships like "when `x` is `0`, `opacity` should be `1`. When `x` is `100` pixels either side, `opacity` should be `0`". const input = \[\-100, 0, 100\] const output = \[0, 1, 0\] Both ranges can be **any length** but must be the **same length** as each other. The input range must always be a series of increasing or decreasing numbers. The output range must be values all of the same type, but can be in any order. It can also be any value type that Motion can animate, like numbers, units, colors and other strings. const backgroundColor = useTransform( x, \[0, 100\], \["#f00", "#00f"\] ) By setting `clamp: false`, the ranges will map perpetually. For instance, in this example we're saying "for every `100px` scrolled, rotate another `360deg`": const { scrollY } = useScroll() const rotate = useTransform( scrollY, \[0, 100\], \[0, 360\], { clamp: false } ) ## Options With value mapping, we can set some additional options. ### `clamp` **Default:** `true` If `true`, will clamp output to within the provided range. If `false`, will carry on mapping even when the input falls outside the provided range. const y = useTransform(x, \[0, 1\], \[0, 2\]) const z = useTransform(x, \[0, 1\], \[0, 2\], { clamp: false }) useEffect(() \=> { x.set(2) console.log(y.get()) // 2, input clamped console.log(z.get()) // 4 }) ### `ease` An easing function, or array of easing functions, to ease the mixing between each value. These must be JavaScript functions. import { cubicBezier, circOut } from "motion" import { useTransform } from "motion/react" // In your component const y = useTransform(x, \[0, 1\], \[0, 2\], { ease: circOut }) const z = useTransform( x, \[0, 1\], \[0, 2\], { ease: cubicBezier(0.17, 0.67, 0.83, 0.67) } ) ### `mixer` A function to use to mix between each pair of output values. This function will be called with each pair of output values and must return a new function, that accepts a progress value between `0` and `1` and returns the mixed value. This can be used to inject more advanced mixers than Framer Motion's default, for instance Flubber for morphing SVG paths. `useTransform` creates a new motion value that transforms the output of one or more motion values. const x = useMotionValue(1) const y = useMotionValue(1) const z = useTransform(() \=> x.get() + y.get()) // z.get() === 2 ## Usage Import from Motion: import { useTransform } from "motion/react" `useTransform` can be used in two ways: with a transform function and via value maps: // Transform function useTransform(() \=> x.get() \* 2) // Value mapping useTransform(x, \[0, 100\], \["#f00", "00f"\]) ### Transform function A transform function is a normal function that returns a value. useTransform(() \=> x.get() \* 2) Any motion values read in this function via the `get()` method will be automatically subscribed to. When these motion values change, the function will be run again on the next animation frame to calculate a new value. const distance = 100 const time = useTime() const y = useTransform(() \=> Math.sin(time.get() / 1000) \* distance) ### Value mapping `useTransform` can also map a single motion value from one range of values to another. To illustrate, look at this `x` motion value: const x = useMotionValue(0) We can use `useTransform` to create a new motion value called `opacity`. const opacity = useTransform(x, input, output) By defining an `input` range and an `output` range, we can define relationships like "when `x` is `0`, `opacity` should be `1`. When `x` is `100` pixels either side, `opacity` should be `0`". const input = \[\-100, 0, 100\] const output = \[0, 1, 0\] Both ranges can be **any length** but must be the **same length** as each other. The input range must always be a series of increasing or decreasing numbers. The output range must be values all of the same type, but can be in any order. It can also be any value type that Motion can animate, like numbers, units, colors and other strings. const backgroundColor = useTransform( x, \[0, 100\], \["#f00", "#00f"\] ) By setting `clamp: false`, the ranges will map perpetually. For instance, in this example we're saying "for every `100px` scrolled, rotate another `360deg`": const { scrollY } = useScroll() const rotate = useTransform( scrollY, \[0, 100\], \[0, 360\], { clamp: false } ) ## Options With value mapping, we can set some additional options. ### `clamp` **Default:** `true` If `true`, will clamp output to within the provided range. If `false`, will carry on mapping even when the input falls outside the provided range. const y = useTransform(x, \[0, 1\], \[0, 2\]) const z = useTransform(x, \[0, 1\], \[0, 2\], { clamp: false }) useEffect(() \=> { x.set(2) console.log(y.get()) // 2, input clamped console.log(z.get()) // 4 }) ### `ease` An easing function, or array of easing functions, to ease the mixing between each value. These must be JavaScript functions. import { cubicBezier, circOut } from "motion" import { useTransform } from "motion/react" // In your component const y = useTransform(x, \[0, 1\], \[0, 2\], { ease: circOut }) const z = useTransform( x, \[0, 1\], \[0, 2\], { ease: cubicBezier(0.17, 0.67, 0.83, 0.67) } ) ### `mixer` A function to use to mix between each pair of output values. This function will be called with each pair of output values and must return a new function, that accepts a progress value between `0` and `1` and returns the mixed value. This can be used to inject more advanced mixers than Framer Motion's default, for instance Flubber for morphing SVG paths. `useTransform` creates a new motion value that transforms the output of one or more motion values. const x = useMotionValue(1) const y = useMotionValue(1) const z = useTransform(() \=> x.get() + y.get()) // z.get() === 2 ## Usage Import from Motion: import { useTransform } from "motion/react" `useTransform` can be used in two ways: with a transform function and via value maps: // Transform function useTransform(() \=> x.get() \* 2) // Value mapping useTransform(x, \[0, 100\], \["#f00", "00f"\]) ### Transform function A transform function is a normal function that returns a value. useTransform(() \=> x.get() \* 2) Any motion values read in this function via the `get()` method will be automatically subscribed to. When these motion values change, the function will be run again on the next animation frame to calculate a new value. const distance = 100 const time = useTime() const y = useTransform(() \=> Math.sin(time.get() / 1000) \* distance) ### Value mapping `useTransform` can also map a single motion value from one range of values to another. To illustrate, look at this `x` motion value: const x = useMotionValue(0) We can use `useTransform` to create a new motion value called `opacity`. const opacity = useTransform(x, input, output) By defining an `input` range and an `output` range, we can define relationships like "when `x` is `0`, `opacity` should be `1`. When `x` is `100` pixels either side, `opacity` should be `0`". const input = \[\-100, 0, 100\] const output = \[0, 1, 0\] Both ranges can be **any length** but must be the **same length** as each other. The input range must always be a series of increasing or decreasing numbers. The output range must be values all of the same type, but can be in any order. It can also be any value type that Motion can animate, like numbers, units, colors and other strings. const backgroundColor = useTransform( x, \[0, 100\], \["#f00", "#00f"\] ) By setting `clamp: false`, the ranges will map perpetually. For instance, in this example we're saying "for every `100px` scrolled, rotate another `360deg`": const { scrollY } = useScroll() const rotate = useTransform( scrollY, \[0, 100\], \[0, 360\], { clamp: false } ) ## Options With value mapping, we can set some additional options. ### `clamp` **Default:** `true` If `true`, will clamp output to within the provided range. If `false`, will carry on mapping even when the input falls outside the provided range. const y = useTransform(x, \[0, 1\], \[0, 2\]) const z = useTransform(x, \[0, 1\], \[0, 2\], { clamp: false }) useEffect(() \=> { x.set(2) console.log(y.get()) // 2, input clamped console.log(z.get()) // 4 }) ### `ease` An easing function, or array of easing functions, to ease the mixing between each value. These must be JavaScript functions. import { cubicBezier, circOut } from "motion" import { useTransform } from "motion/react" // In your component const y = useTransform(x, \[0, 1\], \[0, 2\], { ease: circOut }) const z = useTransform( x, \[0, 1\], \[0, 2\], { ease: cubicBezier(0.17, 0.67, 0.83, 0.67) } ) ### `mixer` A function to use to mix between each pair of output values. This function will be called with each pair of output values and must return a new function, that accepts a progress value between `0` and `1` and returns the mixed value. This can be used to inject more advanced mixers than Framer Motion's default, for instance Flubber for morphing SVG paths. --- ## Page: https://motion.dev/docs/react-use-velocity # useVelocity `useVelocity` accepts a motion value and returns a new one that updates with the provided motion value's velocity. const x = useMotionValue(0) const xVelocity = useVelocity(x) const scale = useTransform( xVelocity, \[\-3000, 0, 3000\], \[2, 1, 2\], { clamp: false } ) return <motion.div drag\="x" style\={{ x, scale }} /> ## Usage Import `useVelocity` from Motion: import { useVelocity } from "motion/react" Pass any numerical motion value to `useVelocity`. It'll return a new motion value that updates with the velocity of the original value. import { useMotionValue, useVelocity } from "framer-motion" function Component() { const x = useMotionValue(0) const xVelocity = useVelocity(x) useMotionValueEvent(xVelocity, "change", latest \=> { console.log("Velocity", latestVelocity) }) return <motion.div style\={{ x }} /> } Any numerical motion value will work. Even one returned from `useVelocity`. const x = useMotionValue(0) const xVelocity = useVelocity(x) const xAcceleration = useVelocity(xVelocity) `useVelocity` accepts a motion value and returns a new one that updates with the provided motion value's velocity. const x = useMotionValue(0) const xVelocity = useVelocity(x) const scale = useTransform( xVelocity, \[\-3000, 0, 3000\], \[2, 1, 2\], { clamp: false } ) return <motion.div drag\="x" style\={{ x, scale }} /> ## Usage Import `useVelocity` from Motion: import { useVelocity } from "motion/react" Pass any numerical motion value to `useVelocity`. It'll return a new motion value that updates with the velocity of the original value. import { useMotionValue, useVelocity } from "framer-motion" function Component() { const x = useMotionValue(0) const xVelocity = useVelocity(x) useMotionValueEvent(xVelocity, "change", latest \=> { console.log("Velocity", latestVelocity) }) return <motion.div style\={{ x }} /> } Any numerical motion value will work. Even one returned from `useVelocity`. const x = useMotionValue(0) const xVelocity = useVelocity(x) const xAcceleration = useVelocity(xVelocity) `useVelocity` accepts a motion value and returns a new one that updates with the provided motion value's velocity. const x = useMotionValue(0) const xVelocity = useVelocity(x) const scale = useTransform( xVelocity, \[\-3000, 0, 3000\], \[2, 1, 2\], { clamp: false } ) return <motion.div drag\="x" style\={{ x, scale }} /> ## Usage Import `useVelocity` from Motion: import { useVelocity } from "motion/react" Pass any numerical motion value to `useVelocity`. It'll return a new motion value that updates with the velocity of the original value. import { useMotionValue, useVelocity } from "framer-motion" function Component() { const x = useMotionValue(0) const xVelocity = useVelocity(x) useMotionValueEvent(xVelocity, "change", latest \=> { console.log("Velocity", latestVelocity) }) return <motion.div style\={{ x }} /> } Any numerical motion value will work. Even one returned from `useVelocity`. const x = useMotionValue(0) const xVelocity = useVelocity(x) const xAcceleration = useVelocity(xVelocity) --- ## Page: https://motion.dev/docs/react-use-animate # useAnimate `useAnimate` provides a way of using the `animate` function that is scoped to the elements within your component. This allows you to use manual animation controls, timelines, selectors scoped to your component, and automatic cleanup. It provides a `scope` ref, and an `animate` function where every DOM selector is scoped to this ref. function Component() { const \[scope, animate\] = useAnimate() useEffect(() \=> { // This "li" selector will only select children // of the element that receives \`scope\`. animate("li", { opacity: 1 }) }) return <ul ref\={scope}\>{children}</ul\> } Additionally, when the component calling `useAnimate` is removed, all animations started with its `animate` function will be cleaned up automatically. ## Usage Import from Motion: // Mini import { useAnimate } from "motion/react-mini" // Hybrid import { useAnimate } from "motion/react" `useAnimate` returns two arguments, a `scope` ref and an `animate` function. function Component() { const \[scope, animate\] = useAnimate() This `scope` ref must be passed to either a regular HTML/SVG element or a `motion` component. function Component({ children }) { const \[scope, animate\] = useAnimate() return <ul ref\={scope}\>{children}</ul\> } This scoped `animate` function can now be used in effects and event handlers to animate elements. We can either use the scoped element directly: animate(scope.current, { opacity: 1 }, { duration: 1 }) Or by passing it a selector: animate("li", { backgroundColor: "#000" }, { ease: "linear" }) This selector is `"li"`, but we're not selecting all `li` elements on the page, only those that are a child of the scoped element. ### Scroll-triggered animations Animations can be triggered when the scope scrolls into view by combining `useAnimate` with `useInView`. import { useAnimate, useInView } from "motion/react" function Component() { const \[scope, animate\] = useAnimate() const isInView = useInView(scope) useEffect(() \=> { if (isInView) { animate(scope.current, { opacity: 1 }) } }, \[isInView\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ### Exit animations It's possible to compose your own exit animations when a component is removed using `useAnimate` in conjunction with `usePresence`. import { useAnimate, usePresence } from "framer-motion" function Component() { const \[isPresent, safeToRemove\] = usePresence() const \[scope, animate\] = useAnimate() useEffect(() \=> { if (isPresent) { const enterAnimation = async () \=> { await animate(scope.current, { opacity: 1 }) await animate("li", { opacity: 1, x: 0 }) } enterAnimation() } else { const exitAnimation = async () \=> { await animate("li", { opacity: 0, x: -100 }) await animate(scope.current, { opacity: 0 }) safeToRemove() } exitAnimation() } }, \[isPresent\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } This component can now be conditionally rendered as a child of `AnimatePresence`. <AnimatePresence\> {show ? <Component key\="dialog" /> : null} </AnimatePresence\> `useAnimate` provides a way of using the `animate` function that is scoped to the elements within your component. This allows you to use manual animation controls, timelines, selectors scoped to your component, and automatic cleanup. It provides a `scope` ref, and an `animate` function where every DOM selector is scoped to this ref. function Component() { const \[scope, animate\] = useAnimate() useEffect(() \=> { // This "li" selector will only select children // of the element that receives \`scope\`. animate("li", { opacity: 1 }) }) return <ul ref\={scope}\>{children}</ul\> } Additionally, when the component calling `useAnimate` is removed, all animations started with its `animate` function will be cleaned up automatically. ## Usage Import from Motion: // Mini import { useAnimate } from "motion/react-mini" // Hybrid import { useAnimate } from "motion/react" `useAnimate` returns two arguments, a `scope` ref and an `animate` function. function Component() { const \[scope, animate\] = useAnimate() This `scope` ref must be passed to either a regular HTML/SVG element or a `motion` component. function Component({ children }) { const \[scope, animate\] = useAnimate() return <ul ref\={scope}\>{children}</ul\> } This scoped `animate` function can now be used in effects and event handlers to animate elements. We can either use the scoped element directly: animate(scope.current, { opacity: 1 }, { duration: 1 }) Or by passing it a selector: animate("li", { backgroundColor: "#000" }, { ease: "linear" }) This selector is `"li"`, but we're not selecting all `li` elements on the page, only those that are a child of the scoped element. ### Scroll-triggered animations Animations can be triggered when the scope scrolls into view by combining `useAnimate` with `useInView`. import { useAnimate, useInView } from "motion/react" function Component() { const \[scope, animate\] = useAnimate() const isInView = useInView(scope) useEffect(() \=> { if (isInView) { animate(scope.current, { opacity: 1 }) } }, \[isInView\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ### Exit animations It's possible to compose your own exit animations when a component is removed using `useAnimate` in conjunction with `usePresence`. import { useAnimate, usePresence } from "framer-motion" function Component() { const \[isPresent, safeToRemove\] = usePresence() const \[scope, animate\] = useAnimate() useEffect(() \=> { if (isPresent) { const enterAnimation = async () \=> { await animate(scope.current, { opacity: 1 }) await animate("li", { opacity: 1, x: 0 }) } enterAnimation() } else { const exitAnimation = async () \=> { await animate("li", { opacity: 0, x: -100 }) await animate(scope.current, { opacity: 0 }) safeToRemove() } exitAnimation() } }, \[isPresent\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } This component can now be conditionally rendered as a child of `AnimatePresence`. <AnimatePresence\> {show ? <Component key\="dialog" /> : null} </AnimatePresence\> `useAnimate` provides a way of using the `animate` function that is scoped to the elements within your component. This allows you to use manual animation controls, timelines, selectors scoped to your component, and automatic cleanup. It provides a `scope` ref, and an `animate` function where every DOM selector is scoped to this ref. function Component() { const \[scope, animate\] = useAnimate() useEffect(() \=> { // This "li" selector will only select children // of the element that receives \`scope\`. animate("li", { opacity: 1 }) }) return <ul ref\={scope}\>{children}</ul\> } Additionally, when the component calling `useAnimate` is removed, all animations started with its `animate` function will be cleaned up automatically. ## Usage Import from Motion: // Mini import { useAnimate } from "motion/react-mini" // Hybrid import { useAnimate } from "motion/react" `useAnimate` returns two arguments, a `scope` ref and an `animate` function. function Component() { const \[scope, animate\] = useAnimate() This `scope` ref must be passed to either a regular HTML/SVG element or a `motion` component. function Component({ children }) { const \[scope, animate\] = useAnimate() return <ul ref\={scope}\>{children}</ul\> } This scoped `animate` function can now be used in effects and event handlers to animate elements. We can either use the scoped element directly: animate(scope.current, { opacity: 1 }, { duration: 1 }) Or by passing it a selector: animate("li", { backgroundColor: "#000" }, { ease: "linear" }) This selector is `"li"`, but we're not selecting all `li` elements on the page, only those that are a child of the scoped element. ### Scroll-triggered animations Animations can be triggered when the scope scrolls into view by combining `useAnimate` with `useInView`. import { useAnimate, useInView } from "motion/react" function Component() { const \[scope, animate\] = useAnimate() const isInView = useInView(scope) useEffect(() \=> { if (isInView) { animate(scope.current, { opacity: 1 }) } }, \[isInView\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } ### Exit animations It's possible to compose your own exit animations when a component is removed using `useAnimate` in conjunction with `usePresence`. import { useAnimate, usePresence } from "framer-motion" function Component() { const \[isPresent, safeToRemove\] = usePresence() const \[scope, animate\] = useAnimate() useEffect(() \=> { if (isPresent) { const enterAnimation = async () \=> { await animate(scope.current, { opacity: 1 }) await animate("li", { opacity: 1, x: 0 }) } enterAnimation() } else { const exitAnimation = async () \=> { await animate("li", { opacity: 0, x: -100 }) await animate(scope.current, { opacity: 0 }) safeToRemove() } exitAnimation() } }, \[isPresent\]) return ( <ul ref\={scope}\> <li /> <li /> <li /> </ul\> ) } This component can now be conditionally rendered as a child of `AnimatePresence`. <AnimatePresence\> {show ? <Component key\="dialog" /> : null} </AnimatePresence\> --- ## Page: https://motion.dev/docs/react-use-animation-frame # useAnimationFrame `useAnimationFrame` runs a callback once every animation frame. useAnimationFrame((time) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) The callback is provided two arguments: * `time`, the total duration of time since the callback was first called. * `delta`, the total duration of time since the last animation frame. import { useAnimationFrame } from "motion/react" function Component() { const ref = useRef(null) useAnimationFrame((time, delta) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) return <div ref\={ref} /> } `useAnimationFrame` runs a callback once every animation frame. useAnimationFrame((time) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) The callback is provided two arguments: * `time`, the total duration of time since the callback was first called. * `delta`, the total duration of time since the last animation frame. import { useAnimationFrame } from "motion/react" function Component() { const ref = useRef(null) useAnimationFrame((time, delta) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) return <div ref\={ref} /> } `useAnimationFrame` runs a callback once every animation frame. useAnimationFrame((time) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) The callback is provided two arguments: * `time`, the total duration of time since the callback was first called. * `delta`, the total duration of time since the last animation frame. import { useAnimationFrame } from "motion/react" function Component() { const ref = useRef(null) useAnimationFrame((time, delta) \=> { ref.current.style.transform = \`rotateY(${time}deg)\` }) return <div ref\={ref} /> } --- ## Page: https://motion.dev/docs/react-use-drag-controls # useDragControls Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop and then moving the pointer. For some use-cases, for example clicking at an arbitrary point on a video scrubber, we might want to initiate that dragging from a different element. With `useDragControls`, we can create a set of controls to manually start dragging from any pointer event. ## Usage Import `useDragControls` from Motion: import { useDragControls } from "motion/react" `useDragControls` returns drag controls that can be passed to a draggable `motion` component: const controls = useDragControls() return <motion.div drag dragControls\={controls} /> Now we can start a drag session from another any element's `onPointerDown` event via the `start` method. <div onPointerDown\={event \=> controls.start(event)} /> ### Touch support To support touch screens, the triggering element should have the `touch-action: none` style applied. <div onPointerDown\={startDrag} style\={{ touchAction: "none" }} /> ### Snap to cursor By default, the drag gesture will only apply **changes** to the pointer position. We can also make the `motion` component immediately snap to the cursor by passing `snapToCursor: true` to the `start` method. controls.start(event, { snapToCursor: true }) ### Disable automatic drag With this configuration, the `motion` component will still automatically start a drag gesture when it receives a `pointerdown` event itself. We can stop this behaviour by passing it a `dragListener={false}` prop. <motion.div drag dragListener\={false} dragControls\={controls} /> Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop and then moving the pointer. For some use-cases, for example clicking at an arbitrary point on a video scrubber, we might want to initiate that dragging from a different element. With `useDragControls`, we can create a set of controls to manually start dragging from any pointer event. ## Usage Import `useDragControls` from Motion: import { useDragControls } from "motion/react" `useDragControls` returns drag controls that can be passed to a draggable `motion` component: const controls = useDragControls() return <motion.div drag dragControls\={controls} /> Now we can start a drag session from another any element's `onPointerDown` event via the `start` method. <div onPointerDown\={event \=> controls.start(event)} /> ### Touch support To support touch screens, the triggering element should have the `touch-action: none` style applied. <div onPointerDown\={startDrag} style\={{ touchAction: "none" }} /> ### Snap to cursor By default, the drag gesture will only apply **changes** to the pointer position. We can also make the `motion` component immediately snap to the cursor by passing `snapToCursor: true` to the `start` method. controls.start(event, { snapToCursor: true }) ### Disable automatic drag With this configuration, the `motion` component will still automatically start a drag gesture when it receives a `pointerdown` event itself. We can stop this behaviour by passing it a `dragListener={false}` prop. <motion.div drag dragListener\={false} dragControls\={controls} /> Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop and then moving the pointer. For some use-cases, for example clicking at an arbitrary point on a video scrubber, we might want to initiate that dragging from a different element. With `useDragControls`, we can create a set of controls to manually start dragging from any pointer event. ## Usage Import `useDragControls` from Motion: import { useDragControls } from "motion/react" `useDragControls` returns drag controls that can be passed to a draggable `motion` component: const controls = useDragControls() return <motion.div drag dragControls\={controls} /> Now we can start a drag session from another any element's `onPointerDown` event via the `start` method. <div onPointerDown\={event \=> controls.start(event)} /> ### Touch support To support touch screens, the triggering element should have the `touch-action: none` style applied. <div onPointerDown\={startDrag} style\={{ touchAction: "none" }} /> ### Snap to cursor By default, the drag gesture will only apply **changes** to the pointer position. We can also make the `motion` component immediately snap to the cursor by passing `snapToCursor: true` to the `start` method. controls.start(event, { snapToCursor: true }) ### Disable automatic drag With this configuration, the `motion` component will still automatically start a drag gesture when it receives a `pointerdown` event itself. We can stop this behaviour by passing it a `dragListener={false}` prop. <motion.div drag dragListener\={false} dragControls\={controls} /> --- ## Page: https://motion.dev/docs/react-use-in-view # useInView `useInView` is a tiny (0.6kb) hook that detects when the provided element is within the viewport. It can be used with any React element. const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> ## Usage Import `useInView` from Motion: import { useInView } from "motion/react" `useInView` can track the visibility of any HTML element. Pass a `ref` object to both `useInView` and the HTML element. function Component() { const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> } While the element is outside the viewport, `useInView` will return `false`. When it moves inside the view, it'll re-render the component and return `true`. ### Effects `useInView` is vanilla React state, so firing functions when `isInView` changes is a matter of passing it to a `useEffect`. useEffect(() \=> { console.log("Element is in view: ", isInView) }, \[isInView\]) ## Options `useInView` can accept options to define how the element is tracked within the viewport. const isInView = useInView(ref, { once: true }) ### `root` By default, `useInView` will track the visibility of an element as it enters/leaves the window viewport. Set `root` to be the ref of a scrollable parent, and it'll use that element to be the viewport instead. function Carousel() { const container = useRef(null) const ref = useRef(null) const isInView = useInView({ root: container }) return ( <div ref\={container} style\={{ overflow: "scroll" }}\> <div ref\={ref} /> </div\> ) } ### `margin` **Default:** `"0px"` A margin to add to the viewport to change the detection area. Use multiple values to adjust top/right/bottom/left, e.g. `"0px -20px 0px 100px"`. const isInView = useInView({ margin: "0px 100px -50px 0px" }) **\]Note:** For browser security reasons, `margin` won't take affect within cross-origin iframes unless `root` is explicitly defined. ### `once` **Default:** `false` If `true`, once an element is in view, useInView will stop observing the element and always return `true`. const isInView = useInView(ref, { once: true }) ### `initial` **Default:** `false` Set an initial value to return until the element has been measured. const isInView = useInView(ref, { initial: true }) ### `amount` **Default:** `"some"` The amount of an element that should enter the viewport to be considered "entered". Either `"some"`, `"all"` or a number between `0` and `1`. ## Example `useInView` is a tiny (0.6kb) hook that detects when the provided element is within the viewport. It can be used with any React element. const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> ## Usage Import `useInView` from Motion: import { useInView } from "motion/react" `useInView` can track the visibility of any HTML element. Pass a `ref` object to both `useInView` and the HTML element. function Component() { const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> } While the element is outside the viewport, `useInView` will return `false`. When it moves inside the view, it'll re-render the component and return `true`. ### Effects `useInView` is vanilla React state, so firing functions when `isInView` changes is a matter of passing it to a `useEffect`. useEffect(() \=> { console.log("Element is in view: ", isInView) }, \[isInView\]) ## Options `useInView` can accept options to define how the element is tracked within the viewport. const isInView = useInView(ref, { once: true }) ### `root` By default, `useInView` will track the visibility of an element as it enters/leaves the window viewport. Set `root` to be the ref of a scrollable parent, and it'll use that element to be the viewport instead. function Carousel() { const container = useRef(null) const ref = useRef(null) const isInView = useInView({ root: container }) return ( <div ref\={container} style\={{ overflow: "scroll" }}\> <div ref\={ref} /> </div\> ) } ### `margin` **Default:** `"0px"` A margin to add to the viewport to change the detection area. Use multiple values to adjust top/right/bottom/left, e.g. `"0px -20px 0px 100px"`. const isInView = useInView({ margin: "0px 100px -50px 0px" }) **\]Note:** For browser security reasons, `margin` won't take affect within cross-origin iframes unless `root` is explicitly defined. ### `once` **Default:** `false` If `true`, once an element is in view, useInView will stop observing the element and always return `true`. const isInView = useInView(ref, { once: true }) ### `initial` **Default:** `false` Set an initial value to return until the element has been measured. const isInView = useInView(ref, { initial: true }) ### `amount` **Default:** `"some"` The amount of an element that should enter the viewport to be considered "entered". Either `"some"`, `"all"` or a number between `0` and `1`. ## Example `useInView` is a tiny (0.6kb) hook that detects when the provided element is within the viewport. It can be used with any React element. const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> ## Usage Import `useInView` from Motion: import { useInView } from "motion/react" `useInView` can track the visibility of any HTML element. Pass a `ref` object to both `useInView` and the HTML element. function Component() { const ref = useRef(null) const isInView = useInView(ref) return <div ref\={ref} /> } While the element is outside the viewport, `useInView` will return `false`. When it moves inside the view, it'll re-render the component and return `true`. ### Effects `useInView` is vanilla React state, so firing functions when `isInView` changes is a matter of passing it to a `useEffect`. useEffect(() \=> { console.log("Element is in view: ", isInView) }, \[isInView\]) ## Options `useInView` can accept options to define how the element is tracked within the viewport. const isInView = useInView(ref, { once: true }) ### `root` By default, `useInView` will track the visibility of an element as it enters/leaves the window viewport. Set `root` to be the ref of a scrollable parent, and it'll use that element to be the viewport instead. function Carousel() { const container = useRef(null) const ref = useRef(null) const isInView = useInView({ root: container }) return ( <div ref\={container} style\={{ overflow: "scroll" }}\> <div ref\={ref} /> </div\> ) } ### `margin` **Default:** `"0px"` A margin to add to the viewport to change the detection area. Use multiple values to adjust top/right/bottom/left, e.g. `"0px -20px 0px 100px"`. const isInView = useInView({ margin: "0px 100px -50px 0px" }) **\]Note:** For browser security reasons, `margin` won't take affect within cross-origin iframes unless `root` is explicitly defined. ### `once` **Default:** `false` If `true`, once an element is in view, useInView will stop observing the element and always return `true`. const isInView = useInView(ref, { once: true }) ### `initial` **Default:** `false` Set an initial value to return until the element has been measured. const isInView = useInView(ref, { initial: true }) ### `amount` **Default:** `"some"` The amount of an element that should enter the viewport to be considered "entered". Either `"some"`, `"all"` or a number between `0` and `1`. ## Example --- ## Page: https://motion.dev/docs/react-use-reduced-motion # useReducedMotion A hook that returns `true` if the current device has Reduced Motion setting enabled. const shouldReduceMotion = useReducedMotion() This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing potentially motion-sickness inducing `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion. It will actively respond to changes and re-render your components with the latest setting. export function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() const closedX = shouldReduceMotion ? 0 : "-100%" return ( <motion.div animate\={{ opacity: isOpen ? 1 : 0, x: isOpen ? 0 : closedX }} /> ) } ## Usage Import `useReducedMotion` from Motion: import { useReducedMotion } from "motion/react" In any component, call `useReducedMotion` to check whether the device's Reduced Motion setting is enabled. const prefersReducedMotion = useReducedMotion() You can then use this `true`/`false` value to change your application logic. A hook that returns `true` if the current device has Reduced Motion setting enabled. const shouldReduceMotion = useReducedMotion() This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing potentially motion-sickness inducing `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion. It will actively respond to changes and re-render your components with the latest setting. export function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() const closedX = shouldReduceMotion ? 0 : "-100%" return ( <motion.div animate\={{ opacity: isOpen ? 1 : 0, x: isOpen ? 0 : closedX }} /> ) } ## Usage Import `useReducedMotion` from Motion: import { useReducedMotion } from "motion/react" In any component, call `useReducedMotion` to check whether the device's Reduced Motion setting is enabled. const prefersReducedMotion = useReducedMotion() You can then use this `true`/`false` value to change your application logic. A hook that returns `true` if the current device has Reduced Motion setting enabled. const shouldReduceMotion = useReducedMotion() This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing potentially motion-sickness inducing `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion. It will actively respond to changes and re-render your components with the latest setting. export function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() const closedX = shouldReduceMotion ? 0 : "-100%" return ( <motion.div animate\={{ opacity: isOpen ? 1 : 0, x: isOpen ? 0 : closedX }} /> ) } ## Usage Import `useReducedMotion` from Motion: import { useReducedMotion } from "motion/react" In any component, call `useReducedMotion` to check whether the device's Reduced Motion setting is enabled. const prefersReducedMotion = useReducedMotion() You can then use this `true`/`false` value to change your application logic. --- ## Page: https://motion.dev/docs/react-upgrade-guide # Upgrade guide We strive to reduce the number of breaking API changes but it is occasionally necessary. The easiest way to upgrade is to start with the version you're currently using, then follow the guide to upgrade to the next version, and so on until you're at the latest version. Changes between major versions are usually small so this is usually a quick process. ## Motion for React ### 12.0 There are no breaking changes in Motion for React in version 12. Please see the JavaScript upgrade guide for changes to the vanilla JS API. ### `"motion/react"` To upgrade to Motion for React, uninstall `framer-motion` and install `motion`: npm uninstall framer\-motion npm install motion Then simply swap imports from `"framer-motion"` to `"motion/react"`: import { motion } from "motion/react" ## Framer Motion ### 11.0 #### Velocity calculation changes In previous versions, setting a `MotionValue` multiple times within the same animation frame would update the value's velocity: const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 100 -> 200 }) This behaviour is incorrect. Synchronous code, practically speaking for the purposes of animation, should be considered instantaneous. Therefore, in the above example, `x` was only `100` for a infinitely small amount of time. It essentially never happened. From version 11, subsequent value updates within synchronous blocks of code won't be considered part of a `MotionValue`'s velocity calculations. Therefore, if `getVelocity` is called after the second update, velocity will be calculated between the latest value and the value at the end of the previous frame. const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 0 -> 200 }) #### Render scheduling changes In previous versions, `motion` components trigger a render synchronously after mount to ensure dynamically-calculated values are updated on-screen. This process has now been moved to a microtask. This ensures that if a component is synchronously re-rendered by a `useLayoutEffect`, the first render is swallowed and we only apply the final one (the one that will be used on-screen). This is better for performance and in most cases won't have practical ramifications for you as a developer. However, there is a caveat for Jest tests. Previously it could be assumed that updates would have applied synchronously. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) expect(element).toHaveStyle("opacity: 1") Tests like this should be updated to await an animation frame. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) await nextFrame() expect(element).toHaveStyle("opacity: 1") // utils.js import { frame } from "framer-motion" export async function nextFrame() { return new Promise<void\>((resolve) \=> { frame.postRender(() \=> resolve()) }) } ### 10.0 #### `IntersectionObserver` fallback This version removes the `IntersectionObserver` fallback behaviour for `whileInView`. `IntersectionObserver` is supported by all modern browsers, representing over 99% of visitors to sites built in Framer. If you require support for legacy browsers like Internet Explorer or Safari 12, we recommend adding an `IntersectionObserver` polyfill. #### `AnimatePresence exitBeforeEnter` prop This prop was deprecated in `7.2.0`. Usage will now throw an error with upgrade instructions (swap to `mode="wait"`). ### 9.0 This version makes **tap events keyboard-accessible**. As a result, all elements with tap listeners or `whileTap` will receive `tabindex="0"`. Reverting this behaviour is discouraged, but can be achieved by passing `tabIndex={-1}`. Additionally, `whileFocus` now behaves like `:focus-visible` rather than `:focus`. Loosely, this means that elements receiving focus via pointer **won't trigger** focus animations, with the exception of input elements which will trigger focus from any input. ### 8.0 Framer Motion uses pointer events to detect tap, drag and hover gestures. In previous versions, these were polyfilled with mouse and touch events in legacy browsers. Version 8 removes this polyfill. As a result, while DragControls.start was always only documented to work with events from `onPointerDown`, it was **typed** to also accept `onMouseDown` and `onTouchStart` events. These will now throw a type error for TypeScript users and should be converted to `onPointerDown`. ### 7.0 Framer Motion 7 makes `react@18` the minimum supported version. Framer Motion 3D users should also upgrade React Three Fiber to `^8.2.2`. ### 6.0 Framer Motion 3D now lives in the `framer-motion-3d` package. So to upgrade to `6.0` simply change imports from `"framer-motion/three"` to `"framer-motion-3d"`. ### 5.0 #### Shared layout animations Framer Motion 5 removes the `AnimateSharedLayout` component. Now, you can use the `layoutId` prop and components will animate from one to another without the need for the `AnimateSharedLayout` wrapper. #### Measuring layout changes Layout changes are detected when a component with a `layout` or `layoutId` prop re-renders. But it isn't performant to measure **all** components when just **one** changes. `AnimateSharedLayout` could be used to group components that affected each other's layout. When one rerendered, `AnimateSharedLayout` would force them all to rerender. This was not a performant approach because all grouped components would perform a re-render. Now, components that affect each other's layout can be grouped with LayoutGroup: import { LayoutGroup, motion } from "framer-motion" export function App() { return ( <LayoutGroup\> <Submenu /> <Submenu /> </LayoutGroup\> ) } function Submenu({ children }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.ul layout style\={{ height: isOpen ? "auto" : 40 }} \> {children} </motion.ul\> ) } Grouped components will be measured whenever one of them renders, but they won't be forced to render themselves. #### Scoped layout animations Previously, because `AnimateSharedLayout` was required, it would naturally scope shared layout animations. So animating between components with the same `layoutId` would only happen within the same `AnimateSharedLayout`: /\*\* \* These items share the same layoutId but won't animate \* between each other because they're children of different \* AnimateSharedLayout components. \*/ <\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> </\> This could lead to very poor performance. `AnimateSharedLayout` reduces layout thrashing within itself by batching layout measurements. But it had no way of batching between many `AnimateSharedLayout` components. The more you add, the more layout thrashing will occur. Now, there is one global tree throughout your app so all layout measurements are batched. But this means all `layoutId`s share the same global context. To bring back this old behaviour you can namespace `layoutId` by providing a `id` prop to `LayoutGroup`: /\*\* \* These layoutIds are now namespaced with \* the id provided to LayoutGroup. \*/ <\> <LayoutGroup id\="a"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> <LayoutGroup id\="b"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> </\> #### Drag to reorder Previous drag-to-reorder implementations were ad-hoc, usually adapted from an old proof-of-concept sandbox that relied on the (now removed) `onViewportBoxUpdate` prop. These solutions should be reimplemented with the new Reorder components. #### ESM and `create-react-app` To enable Framer's experimental "Handshake" features, that allow you to publish no-code components straight from Framer into production, we've moved Framer Motion to ESM modules. Some build environments like `create-react-app` might have some trouble mixing ES modules (like Framer Motion) and CJS modules (like React). To fix, either upgrade to `create-react-app@next`, or downgrade to `framer-motion@4.1.17`. ### 4.0 Framer Motion 4 introduces a brand new `LazyMotion` component to help reduce bundle size. Previously, a subset of `motion` functionality could be loaded in synchronously or asynchronously via `MotionConfig`'s `features` prop. This functionality has been removed in favour of the new `LazyMotion` component. Check out the new reduce bundle size guide to find out how to use this new API. import { LazyMotion, domAnimation, m } from "framer-motion" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimation}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Other breaking changes `4` also removes `motion.custom()`, which was previously deprecated in favour of `motion()`. `motion.custom()` had the default behaviour of forwarding all of Framer Motion's props to the underlying component. To replicate this, the `forwardMotionProps` option can be used. const MotionComponent = motion(Component, { forwardMotionProps: true }) ### 3.0 Framer Motion 3 is major release but the type of breaking change is very specific and very small. It's unlikely, though possible, to change the way your animations function. #### The changing behaviour Motion 3 features a centralisation of how animation states are computed. All animation props are now ranked in terms of priority (left being lowest, right being highest). When one of those props changes, or becomes active/inactive, we will recompute the necessary animations. This is an extension and codification of a behaviour that was partially implemented only for the `while` props, leading to a more consistent and predictable experience. const priority = \["animate", "while-", "exit"\] #### Removing animation values **Before**, if a value was outright removed from an animation prop, nothing would happen. **Now**, if a value is removed, we check for it in the next highest-priority animation state. For instance, if `opacity` is removed from `whileHover`, Motion will check for it in `animate` and animate to that. If we don't find one in `animate`, it'll check in `style`, or fallback to its initially-recorded value (for instance if the value was initially read from the DOM because none was explicitly defined). ### 2.0 Framer Motion 2 is major release and that means there's API changes. In this guide we'll take a look at how you can upgrade your code to ensure it continues to work as expected, and highlight some features that will be broken in the new version of Motion. #### Layout animations Framer Motion 1 supported a couple of ways to perform layout animations, the `positionTransition` and `layoutTransition` props. // Before <motion.div layoutTransition /> In Framer Motion 2, these have both been superseded by the `layout` prop. // After <motion.div layout /> Both of the old props used to take a transition as an argument. // Before <motion.div layoutTransition\={{ duration: 2 }} /> Now, layout animations use the same default `transition` prop as other animations. // After <motion.div layout transition\={{ duration: 2 }} /> In Framer Motion 1, layout animations could distort `borderRadius` and `boxShadow` properties on components that were changing size. This is now fixed if either property is animated. <motion.div layout initial\={{ borderRadius: 20 }} /> Layout animations that changed size could also distort child components. This can now be corrected by providing them with a `layout` prop, too. Only immediate children will need to be corrected for scale. <motion.div layout\> <motion.div layout /> </motion.div\> #### Breaking changes There are some changes that don't have an immediate fix that you should be aware of before upgrading. ##### Drag Drag has been refactored to use the same layout projection rendering methodology that powers Motion 2's layout animations to ensure the two features are fully compatible with each other. This has lead to some breaking changes: * Drag listeners (like `onDrag`) now report the `point` relative to the viewport, moving in line with other pointer gestures in Motion. * `dragOriginX` and `dragOriginY` have been removed. These were added to allow a hacky way to make `positionTransition` compatible with `drag`, but `layout` is compatible with `drag` by default. ##### `useAnimatedState` The `useAnimatedState` API was an experimental and undocumented API for use in Framer X. This has now been removed. We strive to reduce the number of breaking API changes but it is occasionally necessary. The easiest way to upgrade is to start with the version you're currently using, then follow the guide to upgrade to the next version, and so on until you're at the latest version. Changes between major versions are usually small so this is usually a quick process. ## Motion for React ### 12.0 There are no breaking changes in Motion for React in version 12. Please see the JavaScript upgrade guide for changes to the vanilla JS API. ### `"motion/react"` To upgrade to Motion for React, uninstall `framer-motion` and install `motion`: npm uninstall framer\-motion npm install motion Then simply swap imports from `"framer-motion"` to `"motion/react"`: import { motion } from "motion/react" ## Framer Motion ### 11.0 #### Velocity calculation changes In previous versions, setting a `MotionValue` multiple times within the same animation frame would update the value's velocity: const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 100 -> 200 }) This behaviour is incorrect. Synchronous code, practically speaking for the purposes of animation, should be considered instantaneous. Therefore, in the above example, `x` was only `100` for a infinitely small amount of time. It essentially never happened. From version 11, subsequent value updates within synchronous blocks of code won't be considered part of a `MotionValue`'s velocity calculations. Therefore, if `getVelocity` is called after the second update, velocity will be calculated between the latest value and the value at the end of the previous frame. const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 0 -> 200 }) #### Render scheduling changes In previous versions, `motion` components trigger a render synchronously after mount to ensure dynamically-calculated values are updated on-screen. This process has now been moved to a microtask. This ensures that if a component is synchronously re-rendered by a `useLayoutEffect`, the first render is swallowed and we only apply the final one (the one that will be used on-screen). This is better for performance and in most cases won't have practical ramifications for you as a developer. However, there is a caveat for Jest tests. Previously it could be assumed that updates would have applied synchronously. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) expect(element).toHaveStyle("opacity: 1") Tests like this should be updated to await an animation frame. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) await nextFrame() expect(element).toHaveStyle("opacity: 1") // utils.js import { frame } from "framer-motion" export async function nextFrame() { return new Promise<void\>((resolve) \=> { frame.postRender(() \=> resolve()) }) } ### 10.0 #### `IntersectionObserver` fallback This version removes the `IntersectionObserver` fallback behaviour for `whileInView`. `IntersectionObserver` is supported by all modern browsers, representing over 99% of visitors to sites built in Framer. If you require support for legacy browsers like Internet Explorer or Safari 12, we recommend adding an `IntersectionObserver` polyfill. #### `AnimatePresence exitBeforeEnter` prop This prop was deprecated in `7.2.0`. Usage will now throw an error with upgrade instructions (swap to `mode="wait"`). ### 9.0 This version makes **tap events keyboard-accessible**. As a result, all elements with tap listeners or `whileTap` will receive `tabindex="0"`. Reverting this behaviour is discouraged, but can be achieved by passing `tabIndex={-1}`. Additionally, `whileFocus` now behaves like `:focus-visible` rather than `:focus`. Loosely, this means that elements receiving focus via pointer **won't trigger** focus animations, with the exception of input elements which will trigger focus from any input. ### 8.0 Framer Motion uses pointer events to detect tap, drag and hover gestures. In previous versions, these were polyfilled with mouse and touch events in legacy browsers. Version 8 removes this polyfill. As a result, while DragControls.start was always only documented to work with events from `onPointerDown`, it was **typed** to also accept `onMouseDown` and `onTouchStart` events. These will now throw a type error for TypeScript users and should be converted to `onPointerDown`. ### 7.0 Framer Motion 7 makes `react@18` the minimum supported version. Framer Motion 3D users should also upgrade React Three Fiber to `^8.2.2`. ### 6.0 Framer Motion 3D now lives in the `framer-motion-3d` package. So to upgrade to `6.0` simply change imports from `"framer-motion/three"` to `"framer-motion-3d"`. ### 5.0 #### Shared layout animations Framer Motion 5 removes the `AnimateSharedLayout` component. Now, you can use the `layoutId` prop and components will animate from one to another without the need for the `AnimateSharedLayout` wrapper. #### Measuring layout changes Layout changes are detected when a component with a `layout` or `layoutId` prop re-renders. But it isn't performant to measure **all** components when just **one** changes. `AnimateSharedLayout` could be used to group components that affected each other's layout. When one rerendered, `AnimateSharedLayout` would force them all to rerender. This was not a performant approach because all grouped components would perform a re-render. Now, components that affect each other's layout can be grouped with LayoutGroup: import { LayoutGroup, motion } from "framer-motion" export function App() { return ( <LayoutGroup\> <Submenu /> <Submenu /> </LayoutGroup\> ) } function Submenu({ children }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.ul layout style\={{ height: isOpen ? "auto" : 40 }} \> {children} </motion.ul\> ) } Grouped components will be measured whenever one of them renders, but they won't be forced to render themselves. #### Scoped layout animations Previously, because `AnimateSharedLayout` was required, it would naturally scope shared layout animations. So animating between components with the same `layoutId` would only happen within the same `AnimateSharedLayout`: /\*\* \* These items share the same layoutId but won't animate \* between each other because they're children of different \* AnimateSharedLayout components. \*/ <\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> </\> This could lead to very poor performance. `AnimateSharedLayout` reduces layout thrashing within itself by batching layout measurements. But it had no way of batching between many `AnimateSharedLayout` components. The more you add, the more layout thrashing will occur. Now, there is one global tree throughout your app so all layout measurements are batched. But this means all `layoutId`s share the same global context. To bring back this old behaviour you can namespace `layoutId` by providing a `id` prop to `LayoutGroup`: /\*\* \* These layoutIds are now namespaced with \* the id provided to LayoutGroup. \*/ <\> <LayoutGroup id\="a"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> <LayoutGroup id\="b"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> </\> #### Drag to reorder Previous drag-to-reorder implementations were ad-hoc, usually adapted from an old proof-of-concept sandbox that relied on the (now removed) `onViewportBoxUpdate` prop. These solutions should be reimplemented with the new Reorder components. #### ESM and `create-react-app` To enable Framer's experimental "Handshake" features, that allow you to publish no-code components straight from Framer into production, we've moved Framer Motion to ESM modules. Some build environments like `create-react-app` might have some trouble mixing ES modules (like Framer Motion) and CJS modules (like React). To fix, either upgrade to `create-react-app@next`, or downgrade to `framer-motion@4.1.17`. ### 4.0 Framer Motion 4 introduces a brand new `LazyMotion` component to help reduce bundle size. Previously, a subset of `motion` functionality could be loaded in synchronously or asynchronously via `MotionConfig`'s `features` prop. This functionality has been removed in favour of the new `LazyMotion` component. Check out the new reduce bundle size guide to find out how to use this new API. import { LazyMotion, domAnimation, m } from "framer-motion" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimation}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Other breaking changes `4` also removes `motion.custom()`, which was previously deprecated in favour of `motion()`. `motion.custom()` had the default behaviour of forwarding all of Framer Motion's props to the underlying component. To replicate this, the `forwardMotionProps` option can be used. const MotionComponent = motion(Component, { forwardMotionProps: true }) ### 3.0 Framer Motion 3 is major release but the type of breaking change is very specific and very small. It's unlikely, though possible, to change the way your animations function. #### The changing behaviour Motion 3 features a centralisation of how animation states are computed. All animation props are now ranked in terms of priority (left being lowest, right being highest). When one of those props changes, or becomes active/inactive, we will recompute the necessary animations. This is an extension and codification of a behaviour that was partially implemented only for the `while` props, leading to a more consistent and predictable experience. const priority = \["animate", "while-", "exit"\] #### Removing animation values **Before**, if a value was outright removed from an animation prop, nothing would happen. **Now**, if a value is removed, we check for it in the next highest-priority animation state. For instance, if `opacity` is removed from `whileHover`, Motion will check for it in `animate` and animate to that. If we don't find one in `animate`, it'll check in `style`, or fallback to its initially-recorded value (for instance if the value was initially read from the DOM because none was explicitly defined). ### 2.0 Framer Motion 2 is major release and that means there's API changes. In this guide we'll take a look at how you can upgrade your code to ensure it continues to work as expected, and highlight some features that will be broken in the new version of Motion. #### Layout animations Framer Motion 1 supported a couple of ways to perform layout animations, the `positionTransition` and `layoutTransition` props. // Before <motion.div layoutTransition /> In Framer Motion 2, these have both been superseded by the `layout` prop. // After <motion.div layout /> Both of the old props used to take a transition as an argument. // Before <motion.div layoutTransition\={{ duration: 2 }} /> Now, layout animations use the same default `transition` prop as other animations. // After <motion.div layout transition\={{ duration: 2 }} /> In Framer Motion 1, layout animations could distort `borderRadius` and `boxShadow` properties on components that were changing size. This is now fixed if either property is animated. <motion.div layout initial\={{ borderRadius: 20 }} /> Layout animations that changed size could also distort child components. This can now be corrected by providing them with a `layout` prop, too. Only immediate children will need to be corrected for scale. <motion.div layout\> <motion.div layout /> </motion.div\> #### Breaking changes There are some changes that don't have an immediate fix that you should be aware of before upgrading. ##### Drag Drag has been refactored to use the same layout projection rendering methodology that powers Motion 2's layout animations to ensure the two features are fully compatible with each other. This has lead to some breaking changes: * Drag listeners (like `onDrag`) now report the `point` relative to the viewport, moving in line with other pointer gestures in Motion. * `dragOriginX` and `dragOriginY` have been removed. These were added to allow a hacky way to make `positionTransition` compatible with `drag`, but `layout` is compatible with `drag` by default. ##### `useAnimatedState` The `useAnimatedState` API was an experimental and undocumented API for use in Framer X. This has now been removed. We strive to reduce the number of breaking API changes but it is occasionally necessary. The easiest way to upgrade is to start with the version you're currently using, then follow the guide to upgrade to the next version, and so on until you're at the latest version. Changes between major versions are usually small so this is usually a quick process. ## Motion for React ### 12.0 There are no breaking changes in Motion for React in version 12. Please see the JavaScript upgrade guide for changes to the vanilla JS API. ### `"motion/react"` To upgrade to Motion for React, uninstall `framer-motion` and install `motion`: npm uninstall framer\-motion npm install motion Then simply swap imports from `"framer-motion"` to `"motion/react"`: import { motion } from "motion/react" ## Framer Motion ### 11.0 #### Velocity calculation changes In previous versions, setting a `MotionValue` multiple times within the same animation frame would update the value's velocity: const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 100 -> 200 }) This behaviour is incorrect. Synchronous code, practically speaking for the purposes of animation, should be considered instantaneous. Therefore, in the above example, `x` was only `100` for a infinitely small amount of time. It essentially never happened. From version 11, subsequent value updates within synchronous blocks of code won't be considered part of a `MotionValue`'s velocity calculations. Therefore, if `getVelocity` is called after the second update, velocity will be calculated between the latest value and the value at the end of the previous frame. const x = motionValue(0) requestAnimationFrame(() \=> { x.set(100) x.getVelocity() // Velocity of 0 -> 100 x.set(200) x.getVelocity() // Velocity of 0 -> 200 }) #### Render scheduling changes In previous versions, `motion` components trigger a render synchronously after mount to ensure dynamically-calculated values are updated on-screen. This process has now been moved to a microtask. This ensures that if a component is synchronously re-rendered by a `useLayoutEffect`, the first render is swallowed and we only apply the final one (the one that will be used on-screen). This is better for performance and in most cases won't have practical ramifications for you as a developer. However, there is a caveat for Jest tests. Previously it could be assumed that updates would have applied synchronously. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) expect(element).toHaveStyle("opacity: 1") Tests like this should be updated to await an animation frame. render( <motion.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} transition\={{ false }} /> ) await nextFrame() expect(element).toHaveStyle("opacity: 1") // utils.js import { frame } from "framer-motion" export async function nextFrame() { return new Promise<void\>((resolve) \=> { frame.postRender(() \=> resolve()) }) } ### 10.0 #### `IntersectionObserver` fallback This version removes the `IntersectionObserver` fallback behaviour for `whileInView`. `IntersectionObserver` is supported by all modern browsers, representing over 99% of visitors to sites built in Framer. If you require support for legacy browsers like Internet Explorer or Safari 12, we recommend adding an `IntersectionObserver` polyfill. #### `AnimatePresence exitBeforeEnter` prop This prop was deprecated in `7.2.0`. Usage will now throw an error with upgrade instructions (swap to `mode="wait"`). ### 9.0 This version makes **tap events keyboard-accessible**. As a result, all elements with tap listeners or `whileTap` will receive `tabindex="0"`. Reverting this behaviour is discouraged, but can be achieved by passing `tabIndex={-1}`. Additionally, `whileFocus` now behaves like `:focus-visible` rather than `:focus`. Loosely, this means that elements receiving focus via pointer **won't trigger** focus animations, with the exception of input elements which will trigger focus from any input. ### 8.0 Framer Motion uses pointer events to detect tap, drag and hover gestures. In previous versions, these were polyfilled with mouse and touch events in legacy browsers. Version 8 removes this polyfill. As a result, while DragControls.start was always only documented to work with events from `onPointerDown`, it was **typed** to also accept `onMouseDown` and `onTouchStart` events. These will now throw a type error for TypeScript users and should be converted to `onPointerDown`. ### 7.0 Framer Motion 7 makes `react@18` the minimum supported version. Framer Motion 3D users should also upgrade React Three Fiber to `^8.2.2`. ### 6.0 Framer Motion 3D now lives in the `framer-motion-3d` package. So to upgrade to `6.0` simply change imports from `"framer-motion/three"` to `"framer-motion-3d"`. ### 5.0 #### Shared layout animations Framer Motion 5 removes the `AnimateSharedLayout` component. Now, you can use the `layoutId` prop and components will animate from one to another without the need for the `AnimateSharedLayout` wrapper. #### Measuring layout changes Layout changes are detected when a component with a `layout` or `layoutId` prop re-renders. But it isn't performant to measure **all** components when just **one** changes. `AnimateSharedLayout` could be used to group components that affected each other's layout. When one rerendered, `AnimateSharedLayout` would force them all to rerender. This was not a performant approach because all grouped components would perform a re-render. Now, components that affect each other's layout can be grouped with LayoutGroup: import { LayoutGroup, motion } from "framer-motion" export function App() { return ( <LayoutGroup\> <Submenu /> <Submenu /> </LayoutGroup\> ) } function Submenu({ children }) { const \[isOpen, setIsOpen\] = useState(false) return ( <motion.ul layout style\={{ height: isOpen ? "auto" : 40 }} \> {children} </motion.ul\> ) } Grouped components will be measured whenever one of them renders, but they won't be forced to render themselves. #### Scoped layout animations Previously, because `AnimateSharedLayout` was required, it would naturally scope shared layout animations. So animating between components with the same `layoutId` would only happen within the same `AnimateSharedLayout`: /\*\* \* These items share the same layoutId but won't animate \* between each other because they're children of different \* AnimateSharedLayout components. \*/ <\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> <AnimateSharedLayout\> {isVisible ? <motion.div layoutId\="modal" /> : null} </AnimateSharedLayout\> </\> This could lead to very poor performance. `AnimateSharedLayout` reduces layout thrashing within itself by batching layout measurements. But it had no way of batching between many `AnimateSharedLayout` components. The more you add, the more layout thrashing will occur. Now, there is one global tree throughout your app so all layout measurements are batched. But this means all `layoutId`s share the same global context. To bring back this old behaviour you can namespace `layoutId` by providing a `id` prop to `LayoutGroup`: /\*\* \* These layoutIds are now namespaced with \* the id provided to LayoutGroup. \*/ <\> <LayoutGroup id\="a"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> <LayoutGroup id\="b"\> {isVisible ? <motion.div layoutId\="modal" /> : null} </LayoutGroup\> </\> #### Drag to reorder Previous drag-to-reorder implementations were ad-hoc, usually adapted from an old proof-of-concept sandbox that relied on the (now removed) `onViewportBoxUpdate` prop. These solutions should be reimplemented with the new Reorder components. #### ESM and `create-react-app` To enable Framer's experimental "Handshake" features, that allow you to publish no-code components straight from Framer into production, we've moved Framer Motion to ESM modules. Some build environments like `create-react-app` might have some trouble mixing ES modules (like Framer Motion) and CJS modules (like React). To fix, either upgrade to `create-react-app@next`, or downgrade to `framer-motion@4.1.17`. ### 4.0 Framer Motion 4 introduces a brand new `LazyMotion` component to help reduce bundle size. Previously, a subset of `motion` functionality could be loaded in synchronously or asynchronously via `MotionConfig`'s `features` prop. This functionality has been removed in favour of the new `LazyMotion` component. Check out the new reduce bundle size guide to find out how to use this new API. import { LazyMotion, domAnimation, m } from "framer-motion" export const MyComponent = ({ isVisible }) \=> ( <LazyMotion features\={domAnimation}\> <m.div animate\={{ opacity: 1 }} /> </LazyMotion\> ) #### Other breaking changes `4` also removes `motion.custom()`, which was previously deprecated in favour of `motion()`. `motion.custom()` had the default behaviour of forwarding all of Framer Motion's props to the underlying component. To replicate this, the `forwardMotionProps` option can be used. const MotionComponent = motion(Component, { forwardMotionProps: true }) ### 3.0 Framer Motion 3 is major release but the type of breaking change is very specific and very small. It's unlikely, though possible, to change the way your animations function. #### The changing behaviour Motion 3 features a centralisation of how animation states are computed. All animation props are now ranked in terms of priority (left being lowest, right being highest). When one of those props changes, or becomes active/inactive, we will recompute the necessary animations. This is an extension and codification of a behaviour that was partially implemented only for the `while` props, leading to a more consistent and predictable experience. const priority = \["animate", "while-", "exit"\] #### Removing animation values **Before**, if a value was outright removed from an animation prop, nothing would happen. **Now**, if a value is removed, we check for it in the next highest-priority animation state. For instance, if `opacity` is removed from `whileHover`, Motion will check for it in `animate` and animate to that. If we don't find one in `animate`, it'll check in `style`, or fallback to its initially-recorded value (for instance if the value was initially read from the DOM because none was explicitly defined). ### 2.0 Framer Motion 2 is major release and that means there's API changes. In this guide we'll take a look at how you can upgrade your code to ensure it continues to work as expected, and highlight some features that will be broken in the new version of Motion. #### Layout animations Framer Motion 1 supported a couple of ways to perform layout animations, the `positionTransition` and `layoutTransition` props. // Before <motion.div layoutTransition /> In Framer Motion 2, these have both been superseded by the `layout` prop. // After <motion.div layout /> Both of the old props used to take a transition as an argument. // Before <motion.div layoutTransition\={{ duration: 2 }} /> Now, layout animations use the same default `transition` prop as other animations. // After <motion.div layout transition\={{ duration: 2 }} /> In Framer Motion 1, layout animations could distort `borderRadius` and `boxShadow` properties on components that were changing size. This is now fixed if either property is animated. <motion.div layout initial\={{ borderRadius: 20 }} /> Layout animations that changed size could also distort child components. This can now be corrected by providing them with a `layout` prop, too. Only immediate children will need to be corrected for scale. <motion.div layout\> <motion.div layout /> </motion.div\> #### Breaking changes There are some changes that don't have an immediate fix that you should be aware of before upgrading. ##### Drag Drag has been refactored to use the same layout projection rendering methodology that powers Motion 2's layout animations to ensure the two features are fully compatible with each other. This has lead to some breaking changes: * Drag listeners (like `onDrag`) now report the `point` relative to the viewport, moving in line with other pointer gestures in Motion. * `dragOriginX` and `dragOriginY` have been removed. These were added to allow a hacky way to make `positionTransition` compatible with `drag`, but `layout` is compatible with `drag` by default. ##### `useAnimatedState` The `useAnimatedState` API was an experimental and undocumented API for use in Framer X. This has now been removed. --- ## Page: https://motion.dev/docs/react-accessibility # Accessibility Animations can have serious usability implications, even inducing motion sickness in some people. All modern operating systems provide a setting called "Reduced Motion", where people can indicate they prefer less physical motion, either because of personal preference or because they can suffer from motion sickness. There are already some excellent guides about _why_ and _how_ we should design accessible animations, like those at A List Apart and Smashing Magazine. The main takeaways are that for users with "Reduced Motion" enabled, we should keep educational transitions but be aware of motion sickness. That means replacing transform animations on large elements with opacity transitions, disabling auto-playing videos, and disabling parallax animations. Motion for React provides APIs that make it simple to respect these people's preferences. In this guide, we'll learn how to use the `reducedMotion` option and `useReducedMotion` hook to make our animations accessible. ## Automatic The `reducedMotion` option can be set on `MotionConfig` to define how you want to adhere to the Reduced Motion setting. By setting `reducedMotion` it to `"user"`, all `motion` components will **automatically** disable transform and layout animations, while preserving the animation of other values like `opacity` and `backgroundColor`. import { MotionConfig } from "framer-motion" export function App({ children }) { return ( <MotionConfig reducedMotion\="user"\> {children} </MotionConfig\> ) } Framer, the no-code site builder, uses this API and exposes it via a setting in `Site Settings > Accessibility`. Additionally, you can allow a user to override Reduced Motion for just your site by setting reducedMotion to `"always"` or `"never"` based on their profile. <MotionConfig reducedMotion\={userSetting}\> ## Manual While `reducedMotion` is a great blanket tool for ensuring accessible animations across your whole site, more bespoke solutions can be created with the `useReducedMotion` hook. This hook returns `true`/`false` depending on whether your visitor has Reduced Motion enabled. import { useReducedMotion } from "framer-motion" // In your componentconst shouldReduceMotion = useReducedMotion() We can use this boolean to fix some of the common accessibility problems, like the following. ### Replace `transform` with `opacity` When Reduced Motion is enabled on iOS, the operating system still animates between states to help users transition between each context. But instead of the default scale and x/y animations, it fades content in and out. We can achieve this in Motion by passing different values to `animate` based on whether `useReducedMotion` returns `true` or not. function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() let animate if (isOpen) { animate = shouldReduceMotion ? { opacity: 1 } : { x: 0 } } else { animate = shouldReduceMotion ? { opacity: 0 } : { x: "-100%" } } return <motion.div animate\={animate} /> } ### Disable auto-playing video `useReducedMotion` isn’t only compatible with the Motion. It returns a simple boolean, so you can use it for any purpose, like disabling the autoplay of a background `video` element: function BackgroundVideo() { const shouldReduceMotion = useReducedMotion() return <video autoplay\={!shouldReduceMotion} /> } ### Disable parallax Parallax animations can be very unpleasant for people pre-disposed to motion sickness. To build parallax, we usually get `scrollY` from `useViewportScroll`, and create a new `MotionValue` via passing that to `useTransform` which will update's a `motion` component's `y` position as the scroll value changes. To disable this for reduced motion devices, we can conditionally pass this `MotionValue` to the animating element. function Parallax() { const shouldReduceMotion = useReducedMotion() const { scrollY } = useViewportScroll() const y = useTransform(scrollY, \[0, 1\], \[0, -0.2\], { clamp: false, }) return ( <motion.div style\={{ y: shouldReduceMotion ? 0 : y }} /> ) } ## Conclusion We've learned to respect people's Reduced Motion setting with Motion for React. The `reducedMotion` option makes it simple to implement across a whole site, while `useReducedMotion` can help us create bespoke accessibility strategies with any React API. Animations can have serious usability implications, even inducing motion sickness in some people. All modern operating systems provide a setting called "Reduced Motion", where people can indicate they prefer less physical motion, either because of personal preference or because they can suffer from motion sickness. There are already some excellent guides about _why_ and _how_ we should design accessible animations, like those at A List Apart and Smashing Magazine. The main takeaways are that for users with "Reduced Motion" enabled, we should keep educational transitions but be aware of motion sickness. That means replacing transform animations on large elements with opacity transitions, disabling auto-playing videos, and disabling parallax animations. Motion for React provides APIs that make it simple to respect these people's preferences. In this guide, we'll learn how to use the `reducedMotion` option and `useReducedMotion` hook to make our animations accessible. ## Automatic The `reducedMotion` option can be set on `MotionConfig` to define how you want to adhere to the Reduced Motion setting. By setting `reducedMotion` it to `"user"`, all `motion` components will **automatically** disable transform and layout animations, while preserving the animation of other values like `opacity` and `backgroundColor`. import { MotionConfig } from "framer-motion" export function App({ children }) { return ( <MotionConfig reducedMotion\="user"\> {children} </MotionConfig\> ) } Framer, the no-code site builder, uses this API and exposes it via a setting in `Site Settings > Accessibility`. Additionally, you can allow a user to override Reduced Motion for just your site by setting reducedMotion to `"always"` or `"never"` based on their profile. <MotionConfig reducedMotion\={userSetting}\> ## Manual While `reducedMotion` is a great blanket tool for ensuring accessible animations across your whole site, more bespoke solutions can be created with the `useReducedMotion` hook. This hook returns `true`/`false` depending on whether your visitor has Reduced Motion enabled. import { useReducedMotion } from "framer-motion" // In your componentconst shouldReduceMotion = useReducedMotion() We can use this boolean to fix some of the common accessibility problems, like the following. ### Replace `transform` with `opacity` When Reduced Motion is enabled on iOS, the operating system still animates between states to help users transition between each context. But instead of the default scale and x/y animations, it fades content in and out. We can achieve this in Motion by passing different values to `animate` based on whether `useReducedMotion` returns `true` or not. function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() let animate if (isOpen) { animate = shouldReduceMotion ? { opacity: 1 } : { x: 0 } } else { animate = shouldReduceMotion ? { opacity: 0 } : { x: "-100%" } } return <motion.div animate\={animate} /> } ### Disable auto-playing video `useReducedMotion` isn’t only compatible with the Motion. It returns a simple boolean, so you can use it for any purpose, like disabling the autoplay of a background `video` element: function BackgroundVideo() { const shouldReduceMotion = useReducedMotion() return <video autoplay\={!shouldReduceMotion} /> } ### Disable parallax Parallax animations can be very unpleasant for people pre-disposed to motion sickness. To build parallax, we usually get `scrollY` from `useViewportScroll`, and create a new `MotionValue` via passing that to `useTransform` which will update's a `motion` component's `y` position as the scroll value changes. To disable this for reduced motion devices, we can conditionally pass this `MotionValue` to the animating element. function Parallax() { const shouldReduceMotion = useReducedMotion() const { scrollY } = useViewportScroll() const y = useTransform(scrollY, \[0, 1\], \[0, -0.2\], { clamp: false, }) return ( <motion.div style\={{ y: shouldReduceMotion ? 0 : y }} /> ) } ## Conclusion We've learned to respect people's Reduced Motion setting with Motion for React. The `reducedMotion` option makes it simple to implement across a whole site, while `useReducedMotion` can help us create bespoke accessibility strategies with any React API. Animations can have serious usability implications, even inducing motion sickness in some people. All modern operating systems provide a setting called "Reduced Motion", where people can indicate they prefer less physical motion, either because of personal preference or because they can suffer from motion sickness. There are already some excellent guides about _why_ and _how_ we should design accessible animations, like those at A List Apart and Smashing Magazine. The main takeaways are that for users with "Reduced Motion" enabled, we should keep educational transitions but be aware of motion sickness. That means replacing transform animations on large elements with opacity transitions, disabling auto-playing videos, and disabling parallax animations. Motion for React provides APIs that make it simple to respect these people's preferences. In this guide, we'll learn how to use the `reducedMotion` option and `useReducedMotion` hook to make our animations accessible. ## Automatic The `reducedMotion` option can be set on `MotionConfig` to define how you want to adhere to the Reduced Motion setting. By setting `reducedMotion` it to `"user"`, all `motion` components will **automatically** disable transform and layout animations, while preserving the animation of other values like `opacity` and `backgroundColor`. import { MotionConfig } from "framer-motion" export function App({ children }) { return ( <MotionConfig reducedMotion\="user"\> {children} </MotionConfig\> ) } Framer, the no-code site builder, uses this API and exposes it via a setting in `Site Settings > Accessibility`. Additionally, you can allow a user to override Reduced Motion for just your site by setting reducedMotion to `"always"` or `"never"` based on their profile. <MotionConfig reducedMotion\={userSetting}\> ## Manual While `reducedMotion` is a great blanket tool for ensuring accessible animations across your whole site, more bespoke solutions can be created with the `useReducedMotion` hook. This hook returns `true`/`false` depending on whether your visitor has Reduced Motion enabled. import { useReducedMotion } from "framer-motion" // In your componentconst shouldReduceMotion = useReducedMotion() We can use this boolean to fix some of the common accessibility problems, like the following. ### Replace `transform` with `opacity` When Reduced Motion is enabled on iOS, the operating system still animates between states to help users transition between each context. But instead of the default scale and x/y animations, it fades content in and out. We can achieve this in Motion by passing different values to `animate` based on whether `useReducedMotion` returns `true` or not. function Sidebar({ isOpen }) { const shouldReduceMotion = useReducedMotion() let animate if (isOpen) { animate = shouldReduceMotion ? { opacity: 1 } : { x: 0 } } else { animate = shouldReduceMotion ? { opacity: 0 } : { x: "-100%" } } return <motion.div animate\={animate} /> } ### Disable auto-playing video `useReducedMotion` isn’t only compatible with the Motion. It returns a simple boolean, so you can use it for any purpose, like disabling the autoplay of a background `video` element: function BackgroundVideo() { const shouldReduceMotion = useReducedMotion() return <video autoplay\={!shouldReduceMotion} /> } ### Disable parallax Parallax animations can be very unpleasant for people pre-disposed to motion sickness. To build parallax, we usually get `scrollY` from `useViewportScroll`, and create a new `MotionValue` via passing that to `useTransform` which will update's a `motion` component's `y` position as the scroll value changes. To disable this for reduced motion devices, we can conditionally pass this `MotionValue` to the animating element. function Parallax() { const shouldReduceMotion = useReducedMotion() const { scrollY } = useViewportScroll() const y = useTransform(scrollY, \[0, 1\], \[0, -0.2\], { clamp: false, }) return ( <motion.div style\={{ y: shouldReduceMotion ? 0 : y }} /> ) } ## Conclusion We've learned to respect people's Reduced Motion setting with Motion for React. The `reducedMotion` option makes it simple to implement across a whole site, while `useReducedMotion` can help us create bespoke accessibility strategies with any React API. --- ## Page: https://motion.dev/docs/react-reduce-bundle-size # Reduce bundle size A great web experience doesn't just look and move beautifully, it should load quickly, too. When measuring the gzipped and minified size of Motion for React using a bundle analysis website like Bundlephobia, you might see big numbers like **50kb** or more! This is misleading. Motion for React exports many functions, most of which you won't import. JavaScript bundlers like Rollup and Webpack are capable of "tree shaking", which means that only the code you import is shipped to consumers. You may only use a tiny, single hook from Motion for React, like `useReducedMotion`. So in that case the size would be closer to **1kb**. However, Motion for React's primary animation APIs are `useAnimate` and `motion`. Most developers will choose to use at least one of these when using Motion, so let's see how to make them as small as possible. ## `useAnimate` `useAnimate` is Motion for React's animation function, used for manually triggering and controlling animations. It comes in two sizes, **mini** (2.5kb) and **hybrid** (17kb). The mini version exclusively uses WAAPI for hardware accelerated animations, whereas the hybrid function can also animate sequences, motion values, independent transforms and a whole lot more. At 2.5kb, `useAnimate` mini is the smallest animation library available for React. ## `motion` The `motion` component is Motion for React's most common animation API. Because of its declarative, props-driven API, it's impossible for bundlers to tree shake it any smaller than **34kb**. However, by using the `m` and `LazyMotion` components, you can bring this down significantly, to just under **6kb** for the initial render. Then, with lazy-loading, you can defer the loading of animations and interactions until after your site has rendered. **Note:** All sizes quoted in this guide are from Rollup-generated bundles. Webpack is less effective at tree-shaking and should generate slightly larger bundles. ### Reduce size Instead of importing `motion`, import the slimmer `m` component. import \* as m from "motion/react-m" `m` is used in the exact same way as `motion`, but unlike `motion`, the `m` component doesn't come preloaded with features like animations, layout animations, or the drag gesture. Instead, we load these in manually via the `LazyMotion` component. This lets you choose which features you load in, and whether you load them as part of the main bundle, or lazy load them. import { LazyMotion, domAnimation } from "motion/react" // Load only the domAnimation package function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Available features There are currently two **feature packages** you can load: * `domAnimation`: This provides support for animations, variants, exit animations, and tap/hover/focus gestures. (**+15kb**) * `domMax`: This provides support for all of the above, plus pan/drag gestures and layout animations. (**+25kb**) In the future it might be possible to offer more granular feature packages, but for now these were chosen to reduce the amount of duplication between features, which could result in much more data being downloaded ultimately. ### Synchronous loading By passing one of these feature packages to `LazyMotion`, they'll be bundled into your main JavaScript bundle. import { LazyMotion, domAnimation } from "motion/react" function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Lazy loading If you're using a bundler like Webpack or Rollup, we can pass a dynamic import function to `features` that will fetch features only after we've performed our initial render. First, create a file that exports only the features you want to load. // features.js import { domMax } from "motion/react" export default domMax Then, pass `features` a function that will dynamically load that file. import { LazyMotion } from "motion/react" import \* as m from "motion/react-m" // Make sure to return the specific export containing the feature bundle. const loadFeatures = () \=> import("./features.js").then(res \=> res.default) // This animation will run when loadFeatures resolves. function App() { return ( <LazyMotion features\={loadFeatures}\> <m.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </LazyMotion\> ) } ### Strict mode Because the normal `motion` component still preloads all of its functionality, including it anywhere will break the benefits of using `LazyMotion`. To help prevent this, the `strict` prop can be set on `LazyMotion`. If a `motion` component is loaded anywhere within, it will throw with a reminder to render the `m` component instead. function App() { // This will throw! return ( <LazyMotion strict\> <motion.div /> </LazyMotion\> ) } A great web experience doesn't just look and move beautifully, it should load quickly, too. When measuring the gzipped and minified size of Motion for React using a bundle analysis website like Bundlephobia, you might see big numbers like **50kb** or more! This is misleading. Motion for React exports many functions, most of which you won't import. JavaScript bundlers like Rollup and Webpack are capable of "tree shaking", which means that only the code you import is shipped to consumers. You may only use a tiny, single hook from Motion for React, like `useReducedMotion`. So in that case the size would be closer to **1kb**. However, Motion for React's primary animation APIs are `useAnimate` and `motion`. Most developers will choose to use at least one of these when using Motion, so let's see how to make them as small as possible. ## `useAnimate` `useAnimate` is Motion for React's animation function, used for manually triggering and controlling animations. It comes in two sizes, **mini** (2.5kb) and **hybrid** (17kb). The mini version exclusively uses WAAPI for hardware accelerated animations, whereas the hybrid function can also animate sequences, motion values, independent transforms and a whole lot more. At 2.5kb, `useAnimate` mini is the smallest animation library available for React. ## `motion` The `motion` component is Motion for React's most common animation API. Because of its declarative, props-driven API, it's impossible for bundlers to tree shake it any smaller than **34kb**. However, by using the `m` and `LazyMotion` components, you can bring this down significantly, to just under **6kb** for the initial render. Then, with lazy-loading, you can defer the loading of animations and interactions until after your site has rendered. **Note:** All sizes quoted in this guide are from Rollup-generated bundles. Webpack is less effective at tree-shaking and should generate slightly larger bundles. ### Reduce size Instead of importing `motion`, import the slimmer `m` component. import \* as m from "motion/react-m" `m` is used in the exact same way as `motion`, but unlike `motion`, the `m` component doesn't come preloaded with features like animations, layout animations, or the drag gesture. Instead, we load these in manually via the `LazyMotion` component. This lets you choose which features you load in, and whether you load them as part of the main bundle, or lazy load them. import { LazyMotion, domAnimation } from "motion/react" // Load only the domAnimation package function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Available features There are currently two **feature packages** you can load: * `domAnimation`: This provides support for animations, variants, exit animations, and tap/hover/focus gestures. (**+15kb**) * `domMax`: This provides support for all of the above, plus pan/drag gestures and layout animations. (**+25kb**) In the future it might be possible to offer more granular feature packages, but for now these were chosen to reduce the amount of duplication between features, which could result in much more data being downloaded ultimately. ### Synchronous loading By passing one of these feature packages to `LazyMotion`, they'll be bundled into your main JavaScript bundle. import { LazyMotion, domAnimation } from "motion/react" function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Lazy loading If you're using a bundler like Webpack or Rollup, we can pass a dynamic import function to `features` that will fetch features only after we've performed our initial render. First, create a file that exports only the features you want to load. // features.js import { domMax } from "motion/react" export default domMax Then, pass `features` a function that will dynamically load that file. import { LazyMotion } from "motion/react" import \* as m from "motion/react-m" // Make sure to return the specific export containing the feature bundle. const loadFeatures = () \=> import("./features.js").then(res \=> res.default) // This animation will run when loadFeatures resolves. function App() { return ( <LazyMotion features\={loadFeatures}\> <m.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </LazyMotion\> ) } ### Strict mode Because the normal `motion` component still preloads all of its functionality, including it anywhere will break the benefits of using `LazyMotion`. To help prevent this, the `strict` prop can be set on `LazyMotion`. If a `motion` component is loaded anywhere within, it will throw with a reminder to render the `m` component instead. function App() { // This will throw! return ( <LazyMotion strict\> <motion.div /> </LazyMotion\> ) } A great web experience doesn't just look and move beautifully, it should load quickly, too. When measuring the gzipped and minified size of Motion for React using a bundle analysis website like Bundlephobia, you might see big numbers like **50kb** or more! This is misleading. Motion for React exports many functions, most of which you won't import. JavaScript bundlers like Rollup and Webpack are capable of "tree shaking", which means that only the code you import is shipped to consumers. You may only use a tiny, single hook from Motion for React, like `useReducedMotion`. So in that case the size would be closer to **1kb**. However, Motion for React's primary animation APIs are `useAnimate` and `motion`. Most developers will choose to use at least one of these when using Motion, so let's see how to make them as small as possible. ## `useAnimate` `useAnimate` is Motion for React's animation function, used for manually triggering and controlling animations. It comes in two sizes, **mini** (2.5kb) and **hybrid** (17kb). The mini version exclusively uses WAAPI for hardware accelerated animations, whereas the hybrid function can also animate sequences, motion values, independent transforms and a whole lot more. At 2.5kb, `useAnimate` mini is the smallest animation library available for React. ## `motion` The `motion` component is Motion for React's most common animation API. Because of its declarative, props-driven API, it's impossible for bundlers to tree shake it any smaller than **34kb**. However, by using the `m` and `LazyMotion` components, you can bring this down significantly, to just under **6kb** for the initial render. Then, with lazy-loading, you can defer the loading of animations and interactions until after your site has rendered. **Note:** All sizes quoted in this guide are from Rollup-generated bundles. Webpack is less effective at tree-shaking and should generate slightly larger bundles. ### Reduce size Instead of importing `motion`, import the slimmer `m` component. import \* as m from "motion/react-m" `m` is used in the exact same way as `motion`, but unlike `motion`, the `m` component doesn't come preloaded with features like animations, layout animations, or the drag gesture. Instead, we load these in manually via the `LazyMotion` component. This lets you choose which features you load in, and whether you load them as part of the main bundle, or lazy load them. import { LazyMotion, domAnimation } from "motion/react" // Load only the domAnimation package function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Available features There are currently two **feature packages** you can load: * `domAnimation`: This provides support for animations, variants, exit animations, and tap/hover/focus gestures. (**+15kb**) * `domMax`: This provides support for all of the above, plus pan/drag gestures and layout animations. (**+25kb**) In the future it might be possible to offer more granular feature packages, but for now these were chosen to reduce the amount of duplication between features, which could result in much more data being downloaded ultimately. ### Synchronous loading By passing one of these feature packages to `LazyMotion`, they'll be bundled into your main JavaScript bundle. import { LazyMotion, domAnimation } from "motion/react" function App({ children }) { return ( <LazyMotion features\={domAnimation}\> {children} </LazyMotion\> ) } ### Lazy loading If you're using a bundler like Webpack or Rollup, we can pass a dynamic import function to `features` that will fetch features only after we've performed our initial render. First, create a file that exports only the features you want to load. // features.js import { domMax } from "motion/react" export default domMax Then, pass `features` a function that will dynamically load that file. import { LazyMotion } from "motion/react" import \* as m from "motion/react-m" // Make sure to return the specific export containing the feature bundle. const loadFeatures = () \=> import("./features.js").then(res \=> res.default) // This animation will run when loadFeatures resolves. function App() { return ( <LazyMotion features\={loadFeatures}\> <m.div initial\={{ opacity: 0 }} animate\={{ opacity: 1 }} /> </LazyMotion\> ) } ### Strict mode Because the normal `motion` component still preloads all of its functionality, including it anywhere will break the benefits of using `LazyMotion`. To help prevent this, the `strict` prop can be set on `LazyMotion`. If a `motion` component is loaded anywhere within, it will throw with a reminder to render the `m` component instead. function App() { // This will throw! return ( <LazyMotion strict\> <motion.div /> </LazyMotion\> ) } --- ## Page: https://motion.dev/docs/react-three-fiber # Motion for React Three Fiber Deprecated Deprecated Motion for React Three Fiber is a simple yet powerful 3D animation library. It offers most of the same functionality as Motion for React, but for declarative 3D scenes. This guide will help you create animations with Motion for React Three Fiber, but assumes you know the basics of both Motion for React and React Three Fiber. ## Install Motion for React Three Fiber is built upon the Three.js and React Three Fiber (R3F) libraries. Install all three from npm: npm install three@0.137.0 @react\-three/fiber@8.2.2 framer\-motion\-3d@11.2.0 **Warning:** Motion for React Three Fiber is currently only compatible with React 18. ## Usage ### `motion` components For every R3F component, there's a `motion` equivalent. Import `motion` from `"framer-motion-3d"`: import { motion } from "framer-motion-3d" And use in place of your R3F components: <motion.pointLight animate\={{ x: 2 }} /> ### Animation Motion for R3F supports all the same animation options as usual, including the `initial` and `animate` props, `exit` and variants. const variants = { hidden: { opacity: 0 }, visible: { opacity: 1 }, } return ( <motion.meshStandardMaterial initial\="hidden" animate\="visible" variants\={variants} /> ) Currently, variants can't be automatically passed between the DOM and 3D worlds, but you can still share state to achieve similar results: // index.js import { motion } from "framer-motion" import { Scene } from "./scene" export function App() { const \[isHovered, setIsHovered\] = useState(false) return ( <motion.div whileHover\={{ scale: 1.2 }} onHoverStart\={() \=> setIsHovered(true)} onHoverEnd\={() \=> setIsHovered(true)} \> <Scene isHovered\={isHovered} /> </motion.div\> ) } // scene.js import { Canvas } from "@react-three/fiber" import { motion } from "framer-motion-3d" export function Scene({ isHovered }) { return ( <Canvas\> <motion.group animate\={isHovered ? "hover" : "rest"}\> <motion.mesh variants\={{ hover: { z: 1 } }} /> </motion.group\> </Canvas\> ) } ### Supported values 3D `motion` components support most of the the same transforms as their 2D equivalents: * `x`, `y` and `z` * `scale`, `scaleX`, `scaleY` and `scaleZ` * `rotateX`, `rotateY` and `rotateZ` Additionally, `color` and `opacity` are supported on 3D primitives that support them, like `meshStandardMaterial`, with support for more values coming in the near future. ### Gestures 3D `motion` components support the hover and tap gestures on R3F with a physical presence (like `mesh`). <motion.mesh whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} onHoverStart\={() \=> console.log('hover start')} onTap\={() \=> console.log('tapped!')} /> ### Motion values Motion values are used to track the state and velocity of animating values, outside of React's render lifecycle. With 3D `motion` components, motion values are injected via their R3F attribute: import { useMotionValue, useTransform } from "framer-motion" import { motion } from "framer-motion-3d" export function Box() { const x = useMotionValue(0) const scaleZ = useTransform(x, v \=> v / 100) return ( <motion.mesh position-x\={x} scale\={\[1, 1, scaleZ\]} animate\={{ x: 100 }} /> ) } ### Layout animations Images, and therefore 3D scenes, involved in layout animations can exhibit scale distortion. With the `LayoutCamera` and `LayoutOrthographicCamera` components this distortion can be corrected and the 3D scene can be incorporated into the layout animation naturally. Motion for React Three Fiber is a simple yet powerful 3D animation library. It offers most of the same functionality as Motion for React, but for declarative 3D scenes. This guide will help you create animations with Motion for React Three Fiber, but assumes you know the basics of both Motion for React and React Three Fiber. ## Install Motion for React Three Fiber is built upon the Three.js and React Three Fiber (R3F) libraries. Install all three from npm: npm install three@0.137.0 @react\-three/fiber@8.2.2 framer\-motion\-3d@11.2.0 **Warning:** Motion for React Three Fiber is currently only compatible with React 18. ## Usage ### `motion` components For every R3F component, there's a `motion` equivalent. Import `motion` from `"framer-motion-3d"`: import { motion } from "framer-motion-3d" And use in place of your R3F components: <motion.pointLight animate\={{ x: 2 }} /> ### Animation Motion for R3F supports all the same animation options as usual, including the `initial` and `animate` props, `exit` and variants. const variants = { hidden: { opacity: 0 }, visible: { opacity: 1 }, } return ( <motion.meshStandardMaterial initial\="hidden" animate\="visible" variants\={variants} /> ) Currently, variants can't be automatically passed between the DOM and 3D worlds, but you can still share state to achieve similar results: // index.js import { motion } from "framer-motion" import { Scene } from "./scene" export function App() { const \[isHovered, setIsHovered\] = useState(false) return ( <motion.div whileHover\={{ scale: 1.2 }} onHoverStart\={() \=> setIsHovered(true)} onHoverEnd\={() \=> setIsHovered(true)} \> <Scene isHovered\={isHovered} /> </motion.div\> ) } // scene.js import { Canvas } from "@react-three/fiber" import { motion } from "framer-motion-3d" export function Scene({ isHovered }) { return ( <Canvas\> <motion.group animate\={isHovered ? "hover" : "rest"}\> <motion.mesh variants\={{ hover: { z: 1 } }} /> </motion.group\> </Canvas\> ) } ### Supported values 3D `motion` components support most of the the same transforms as their 2D equivalents: * `x`, `y` and `z` * `scale`, `scaleX`, `scaleY` and `scaleZ` * `rotateX`, `rotateY` and `rotateZ` Additionally, `color` and `opacity` are supported on 3D primitives that support them, like `meshStandardMaterial`, with support for more values coming in the near future. ### Gestures 3D `motion` components support the hover and tap gestures on R3F with a physical presence (like `mesh`). <motion.mesh whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} onHoverStart\={() \=> console.log('hover start')} onTap\={() \=> console.log('tapped!')} /> ### Motion values Motion values are used to track the state and velocity of animating values, outside of React's render lifecycle. With 3D `motion` components, motion values are injected via their R3F attribute: import { useMotionValue, useTransform } from "framer-motion" import { motion } from "framer-motion-3d" export function Box() { const x = useMotionValue(0) const scaleZ = useTransform(x, v \=> v / 100) return ( <motion.mesh position-x\={x} scale\={\[1, 1, scaleZ\]} animate\={{ x: 100 }} /> ) } ### Layout animations Images, and therefore 3D scenes, involved in layout animations can exhibit scale distortion. With the `LayoutCamera` and `LayoutOrthographicCamera` components this distortion can be corrected and the 3D scene can be incorporated into the layout animation naturally. Motion for React Three Fiber is a simple yet powerful 3D animation library. It offers most of the same functionality as Motion for React, but for declarative 3D scenes. This guide will help you create animations with Motion for React Three Fiber, but assumes you know the basics of both Motion for React and React Three Fiber. ## Install Motion for React Three Fiber is built upon the Three.js and React Three Fiber (R3F) libraries. Install all three from npm: npm install three@0.137.0 @react\-three/fiber@8.2.2 framer\-motion\-3d@11.2.0 **Warning:** Motion for React Three Fiber is currently only compatible with React 18. ## Usage ### `motion` components For every R3F component, there's a `motion` equivalent. Import `motion` from `"framer-motion-3d"`: import { motion } from "framer-motion-3d" And use in place of your R3F components: <motion.pointLight animate\={{ x: 2 }} /> ### Animation Motion for R3F supports all the same animation options as usual, including the `initial` and `animate` props, `exit` and variants. const variants = { hidden: { opacity: 0 }, visible: { opacity: 1 }, } return ( <motion.meshStandardMaterial initial\="hidden" animate\="visible" variants\={variants} /> ) Currently, variants can't be automatically passed between the DOM and 3D worlds, but you can still share state to achieve similar results: // index.js import { motion } from "framer-motion" import { Scene } from "./scene" export function App() { const \[isHovered, setIsHovered\] = useState(false) return ( <motion.div whileHover\={{ scale: 1.2 }} onHoverStart\={() \=> setIsHovered(true)} onHoverEnd\={() \=> setIsHovered(true)} \> <Scene isHovered\={isHovered} /> </motion.div\> ) } // scene.js import { Canvas } from "@react-three/fiber" import { motion } from "framer-motion-3d" export function Scene({ isHovered }) { return ( <Canvas\> <motion.group animate\={isHovered ? "hover" : "rest"}\> <motion.mesh variants\={{ hover: { z: 1 } }} /> </motion.group\> </Canvas\> ) } ### Supported values 3D `motion` components support most of the the same transforms as their 2D equivalents: * `x`, `y` and `z` * `scale`, `scaleX`, `scaleY` and `scaleZ` * `rotateX`, `rotateY` and `rotateZ` Additionally, `color` and `opacity` are supported on 3D primitives that support them, like `meshStandardMaterial`, with support for more values coming in the near future. ### Gestures 3D `motion` components support the hover and tap gestures on R3F with a physical presence (like `mesh`). <motion.mesh whileHover\={{ scale: 1.1 }} whileTap\={{ scale: 0.9 }} onHoverStart\={() \=> console.log('hover start')} onTap\={() \=> console.log('tapped!')} /> ### Motion values Motion values are used to track the state and velocity of animating values, outside of React's render lifecycle. With 3D `motion` components, motion values are injected via their R3F attribute: import { useMotionValue, useTransform } from "framer-motion" import { motion } from "framer-motion-3d" export function Box() { const x = useMotionValue(0) const scaleZ = useTransform(x, v \=> v / 100) return ( <motion.mesh position-x\={x} scale\={\[1, 1, scaleZ\]} animate\={{ x: 100 }} /> ) } ### Layout animations Images, and therefore 3D scenes, involved in layout animations can exhibit scale distortion. With the `LayoutCamera` and `LayoutOrthographicCamera` components this distortion can be corrected and the 3D scene can be incorporated into the layout animation naturally. --- ## Page: https://motion.dev/docs/react-three-fiber-motion-canvas # MotionCanvas Deprecated Deprecated React Three Fiber (R3F) uses the Canvas component to establish a 3D scene. Using this component will break context with parent components. To link Motion 3D context with DOM Motion, for example to share a default transition or link the LayoutCamera with layout animations, the `MotionCanvas` component can be used instead. import { MotionConfig, motion } from "motion/react" import { MotionCanvas, motion as motion3d } from "framer-motion-3d" export function App() { return ( <MotionConfig transition\={{ type: "spring" }}\> <motion.div animate\={{ scale: 2 }}\> <MotionCanvas\> <motion3d.boxGeometry animate\={{ x: 1 }} /> </MotionCanvas\> </motion.div\> </MotionConfig\> ) } It shares all the same props as R3F's `Canvas` component, with the omission of `resize`, as `MotionCanvas` implements its own resize options to sync with Framer Motion's layout animations. It's also mandatory to enable 3D scenes within layout animations. React Three Fiber (R3F) uses the Canvas component to establish a 3D scene. Using this component will break context with parent components. To link Motion 3D context with DOM Motion, for example to share a default transition or link the LayoutCamera with layout animations, the `MotionCanvas` component can be used instead. import { MotionConfig, motion } from "motion/react" import { MotionCanvas, motion as motion3d } from "framer-motion-3d" export function App() { return ( <MotionConfig transition\={{ type: "spring" }}\> <motion.div animate\={{ scale: 2 }}\> <MotionCanvas\> <motion3d.boxGeometry animate\={{ x: 1 }} /> </MotionCanvas\> </motion.div\> </MotionConfig\> ) } It shares all the same props as R3F's `Canvas` component, with the omission of `resize`, as `MotionCanvas` implements its own resize options to sync with Framer Motion's layout animations. It's also mandatory to enable 3D scenes within layout animations. React Three Fiber (R3F) uses the Canvas component to establish a 3D scene. Using this component will break context with parent components. To link Motion 3D context with DOM Motion, for example to share a default transition or link the LayoutCamera with layout animations, the `MotionCanvas` component can be used instead. import { MotionConfig, motion } from "motion/react" import { MotionCanvas, motion as motion3d } from "framer-motion-3d" export function App() { return ( <MotionConfig transition\={{ type: "spring" }}\> <motion.div animate\={{ scale: 2 }}\> <MotionCanvas\> <motion3d.boxGeometry animate\={{ x: 1 }} /> </MotionCanvas\> </motion.div\> </MotionConfig\> ) } It shares all the same props as R3F's `Canvas` component, with the omission of `resize`, as `MotionCanvas` implements its own resize options to sync with Framer Motion's layout animations. It's also mandatory to enable 3D scenes within layout animations. --- ## Page: https://motion.dev/docs/react-three-fiber-layout-cameras # Layout cameras Deprecated Deprecated `LayoutCamera` and `LayoutOrthographicCamera` allow us to involve React Three Fiber scenes in Motion's layout animations. ## Usage Motion's layout animations work via the `transform` style. A drawback to animating `width` and `height` via `transform` is imagery can become distorted. When involving a React Three Fiber scene into a layout animation, we can use Motion's `LayoutCamera` and `LayoutOrthographicCamera` components to pre-distort a 3D scene so that when the CSS `transform` is applied to the host `canvas` element, it looks correct throughout the animation. To implement a camera, we first nee to replace `Canvas` from `@react-three/fiber` with the `MotionCanvas` component. Then, one of the camera components can be added anywhere within the scene: import { MotionCanvas, LayoutCamera } from "framer-motion" function Scene() { <MotionCanvas\> <LayoutCamera /> <Box /> </MotionCanvas\> } `LayoutCamera` provides a normal perspective camera: Whereas `LayoutOrthographicCamera` provides an orthographic view: ## Props Internally, `LayoutCamera` renders a `<motion.perspectiveCamera />` and `LayoutOrthographicCamera` renders a `<motion.orthographicCamera />` component, so they can accept all the usual React Three Fiber props like `position` and `zoom`, as well as `motion` props like `initial` and `animate`. <LayoutCamera position\={\[0, 0, 5\]} zoom\={20} animate\={{ zoom: 100 }} transition\={{ duration: 2 }} /> `LayoutCamera` and `LayoutOrthographicCamera` allow us to involve React Three Fiber scenes in Motion's layout animations. ## Usage Motion's layout animations work via the `transform` style. A drawback to animating `width` and `height` via `transform` is imagery can become distorted. When involving a React Three Fiber scene into a layout animation, we can use Motion's `LayoutCamera` and `LayoutOrthographicCamera` components to pre-distort a 3D scene so that when the CSS `transform` is applied to the host `canvas` element, it looks correct throughout the animation. To implement a camera, we first nee to replace `Canvas` from `@react-three/fiber` with the `MotionCanvas` component. Then, one of the camera components can be added anywhere within the scene: import { MotionCanvas, LayoutCamera } from "framer-motion" function Scene() { <MotionCanvas\> <LayoutCamera /> <Box /> </MotionCanvas\> } `LayoutCamera` provides a normal perspective camera: Whereas `LayoutOrthographicCamera` provides an orthographic view: ## Props Internally, `LayoutCamera` renders a `<motion.perspectiveCamera />` and `LayoutOrthographicCamera` renders a `<motion.orthographicCamera />` component, so they can accept all the usual React Three Fiber props like `position` and `zoom`, as well as `motion` props like `initial` and `animate`. <LayoutCamera position\={\[0, 0, 5\]} zoom\={20} animate\={{ zoom: 100 }} transition\={{ duration: 2 }} /> `LayoutCamera` and `LayoutOrthographicCamera` allow us to involve React Three Fiber scenes in Motion's layout animations. ## Usage Motion's layout animations work via the `transform` style. A drawback to animating `width` and `height` via `transform` is imagery can become distorted. When involving a React Three Fiber scene into a layout animation, we can use Motion's `LayoutCamera` and `LayoutOrthographicCamera` components to pre-distort a 3D scene so that when the CSS `transform` is applied to the host `canvas` element, it looks correct throughout the animation. To implement a camera, we first nee to replace `Canvas` from `@react-three/fiber` with the `MotionCanvas` component. Then, one of the camera components can be added anywhere within the scene: import { MotionCanvas, LayoutCamera } from "framer-motion" function Scene() { <MotionCanvas\> <LayoutCamera /> <Box /> </MotionCanvas\> } `LayoutCamera` provides a normal perspective camera: Whereas `LayoutOrthographicCamera` provides an orthographic view: ## Props Internally, `LayoutCamera` renders a `<motion.perspectiveCamera />` and `LayoutOrthographicCamera` renders a `<motion.orthographicCamera />` component, so they can accept all the usual React Three Fiber props like `position` and `zoom`, as well as `motion` props like `initial` and `animate`. <LayoutCamera position\={\[0, 0, 5\]} zoom\={20} animate\={{ zoom: 100 }} transition\={{ duration: 2 }} />