Layout Animation In Framer Motion
Layout animations in Framer Motion allow you to create smooth transitions when the layout of your components changes. This is particularly useful for dynamic UIs where elements may be added, removed, or reordered.
How it works
Framer Motion provides a layout prop that can be added to motion components. When the layout of these components changes (due to state changes, window resizing, etc.), Framer Motion automatically animates the transition between the old and new layouts which means we have initial and final position of the element and framer motion will take care of animating between those two positions like morph animation.
Setting Up Layout Animations
To set up layout animations in Framer Motion, follow these steps:
- Import Modules: Import the necessary modules from Framer Motion.
- Wrap Components: Wrap the components you want to animate with motion elements.
- Add Layout Prop: Add the layout prop to the motion components that should animate on layout changes.
- Trigger Changes with State: Use state management to trigger layout changes dynamically.
Note: Always apply layout changes through styles for proper animation. Note: The layout animation doesnt work with inline elements like span, strong etc. It works with block elements like div, section, article etc. so if you are working with inline elements then make sure to change their display property to block or inline-block.
Example of Layout Animation
import React from "react";
import { AnimatePresence, easeIn, motion } from "framer-motion";
import { Send } from "lucide-react";
const App = () => {
const [open, setIsOpen] = React.useState(false);
return (
<motion.div className="h-screen bg-black mx-auto text-black flex items-center justify-center">
<div className="flex space-x-2.5 w-1/3">
<input
className="outline-none grow bg-white p-3 rounded-2xl"
style={{
width: open ? "100%" : "0%",
opacity: open ? 1 : 0,
padding: open ? "0.75rem" : "0",
}}
/>
<motion.button
style={{
width: open ? "20%" : "100%",
}}
layout
onClick={() => setIsOpen(!open)}
className="bg-white p-3 rounded-2xl cursor-pointer"
>
<motion.span className="flex space-x-5" layout>
<motion.span layout>
<Send />
</motion.span>
{!open && (
<motion.span
layout
initial={{ opacity: 0, x: -15 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -15 }}
transition={{
opacity: {
type: "spring",
},
}}
>
Send a message
</motion.span>
)}
</motion.span>
</motion.button>
</div>
</motion.div>
);
};
export default App;
Another Example
import React from "react";
import { motion } from "framer-motion";
const App = () => {
const [toggle, setToggle] = React.useState(true);
return (
<div className="w-full h-screen flex justify-center items-center">
<motion.div
layout
className="bg-pink-400 flex px-10 py-3 space-x-4 rounded-xl space-y-4 items-center"
style={{
flexDirection: toggle ? "row" : "column",
padding: toggle ? "20px 40px" : "40px 40px",
}}
>
<motion.video
layout
src="https://media.istockphoto.com/id/1330803052/video/seamless-loop-blue-neon-glowing-loading-bar-progress-download-circle-on-black-background.mp4?s=mp4-640x640-is&k=20&c=yuolHV_L9r1u2jFIGj89kWbrNGBy1sYu5Lrm540IuVo="
autoPlay
loop
muted
className=" h-10 rounded-full"
></motion.video>
<motion.div layout className="flex flex-col ">
<motion.h2 layout className="font-bold">Playing now</motion.h2>
<motion.span layout>Dil ki darya</motion.span>
</motion.div>
</motion.div>
<button
onClick={() => {
setToggle((s) => !s);
}}
className="absolute bottom-0 px-5 rounded-xl cursor-pointer py-4 mb-10 bg-pink-400 border-none"
>
Toggle
</button>
</div>
);
};
export default App;
Animating the border radius with layout animation
If we want to animate the border radius of a component in layout animation animate it using animate prop if you doesnt want to change the border radius then simply add the border radius inside the style object.
Example1:
<motion.div
layout
animate={{
borderRadius: isOpen ? "20px" : "50%",
}}>
Box
</motion.div>
Example2:
<motion.div
layout
style={{
borderRadius: "20px",
}}>
Box
</motion.div>
Variations of layout prop
layout: This will animate the position and size changes of the component.layout="position": This will animate only the position changes of the component, not the size.layout="size": This will animate only the size changes of the component, not the position.layout= "preserve-aspect": This will animate the size changes of the component while preserving its aspect ratio.