Framer Motion Animations Guide: Effortless Web Animation for React
Dive into the world of dynamic web interfaces with this Framer Motion animations guide, your ultimate resource for creating captivating experiences in React. We'll explore how Framer Motion simplifies the process of adding smooth, engaging animations to your web applications. From basic fade-ins and transitions to complex gesture-based and scroll-triggered animations, this guide provides practical examples and clear explanations to get you started. Discover how to leverage this powerful library to elevate your user interfaces and bring your designs to life.
This Framer Motion animations guide focuses on practical application and understanding of core concepts. We'll cover everything from setting up your environment and importing necessary components to creating sophisticated animations that respond to user interactions and scrolling behavior. You'll learn how to control animation properties like duration, easing, and delay, and how to organize your code for better readability and reusability. Get ready to transform your static websites into dynamic, interactive experiences!
What This Guide Covers
This article will focus on:
- Getting started with Framer Motion
- Gestures (onClick, onHover, etc.)
- Scroll-triggered animations
Getting Started with Framer Motion
Framer Motion is a production-ready motion library for React. It allows you to easily create animations and transitions in your React applications. Let's walk through the initial setup and understand the core concepts.
Step 1: Install Framer Motion
Begin by creating a React or Next.js app (if you haven't already). Then, install Framer Motion using npm or yarn:
npm install framer-motion
or
yarn add framer-motion
Step 2: Import the motion
component
To use Framer Motion, import the motion
component from the library:
import { motion } from "framer-motion"
Before diving into animation creation with Framer Motion, it’s essential to understand how animations are constructed. The library offers a range of components like motion.div
, motion.button
, motion.p
, etc. They work exactly like their static counterparts but offer special animation props such as animate
, transition
, hover & tap gestures and much more.
<motion.div />
Note for Next.js developers: You'll need to add the "use client"
directive in all files where the motion
component is being used. This is because Framer Motion uses effects and other client-side features, so it can’t be used as a server component.
Example 1: Fade-in animation
Let's create a simple fade-in animation to get started.
'use client';
import { motion } from 'framer-motion';
export default function MyComponent(){
return (
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }}
className='w-20 h-20 bg-yellow-400 rounded-lg'
>
</motion.div>
);
}
In the above code snippet, a fade-in animation with a y-axis translation is defined. The div
initially has an opacity of zero and is translated -50px on the y-axis. It’s then animated to opacity 1 and its original position.
It’s crucial to note that only the animate
prop is responsible for the animation. Thus, all styles you wish to animate must be defined here.
The initial
prop is used to define the initial styles of the element that would already be there when the component loads. After that, the animate
prop takes over and does the work of animating those values to the ones we have defined. The initial
property establishes the starting point for the animation, setting the stage for the transition to the animate
state.
Example 2: Animating Between Multiple Values
So far, we’ve only animated between two values, from initial
to animate
. But what if we want to create a more complex animation where we animate between multiple values? We can achieve that by providing an array of different values. For example:
'use client';
import { motion } from 'framer-motion';
export default function MyComponent() {
return (
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: [0, 1, 1, 0], y: [-50, 0, 0, 50] }}
className='w-20 h-20 bg-yellow-400 rounded-lg'
>
</motion.div>
);
}
In the above code snippet, we've defined an initial style for the div
. Subsequently, the opacity animates from 0 to 1 and then from 1 back to 0. Similarly, the div
translates on the y-axis from -50px to 0 and then from 0 to 50px. This arrangement creates an effect where the animation progresses like a timeline.
By using animation between multiple values, you can easily create complex animations. For example, animating between multiple values for background color, border-radius, and rotation for the z-axis can create a dynamic and visually appealing effect.
Controlling Animation Properties
Framer Motion allows control over properties such as duration
, easing
, delay
, staggerChildren
, loop
, repeat
, etc., using the transition
prop. These properties fine-tune the animation's behavior and timing.
Transition Properties
Transition props are applied to the entire animation when used like this:
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: [0, 1, 1, 0], y: [-50, 0, 0, 50] }}
transition={{ duration: 1.5, ease: 'easeOut', delay: 0.75 }}
className='w-60 h-60 bg-yellow-500 rounded-lg'
>
</motion.div>
You can specify individual transition props for each style property:
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: [0, 1, 1, 0], y: [-50, 0, 0, 50] }}
transition={{
y: { duration: 2.5, ease: 'easeOut' },
opacity: { duration: 2 , ease: 'easeIn', delay: 0.5 },
}}
className='w-60 h-60 bg-yellow-500 rounded-lg'
>
</motion.div>
Framer Motion provides several values for the ease
property. Additionally, custom easing functions can be defined using an array, for example:
transition={{ ease: [0.20, 0.70, 0.80, 0.75] }}
Organizing Animations with Variants
Before we move to gesture animations, it's time to address readability issues with these animation definitions. So far, we’ve been defining the initial
, animate
, and transition
props on the motion
component directly. As some of you might have noticed, this could be really bad when we need to change something or when we have a certain animation that we want all over our app. A button animation is a good example for such a situation. So, to maintain the readability and quality of our code, animations and transitions can be defined separately and reused:
export const myAnimation = {
initial: { opacity: 0, y: -50 },
animate: { opacity: [0, 1, 1, 1], y: [-50, 0, 0, 50] },
};
export const myTransition = {
y: { duration: 2.5, ease: 'easeOut'},
opacity: { duration: 2, ease: 'easeIn', delay: 0.5 }
};
<motion.div
initial='initial'
animate='animate'
variants={myAnimation}
transition={myTransition}
className='w-60 h-60 bg-yellow-500 rounded-lg'
>
</motion.div>
Here, animations and transitions are defined separately. The variants
prop is used to specify the animation, enhancing code reusability. variants
is another prop that’s accepted by the motion
component. Variants are pre-defined animation states that can be re-used. Once we provide a variant to the motion
component, we can specify the values for initial
, animate
, exit
, and the gesture props with their respective animation in the variant.
Gesture Animations
In addition to simple animations, Framer Motion offers support for gesture animation. These gestures include hover, tap, pan, and drag.
We will focus on tap
, hover
, and focus
.
These gesture animations are implemented through motion
components, which provide multiple gesture animation props such as whileHover
, whileTap
, whileFocus
, etc. Let's delve into them:
whileHover
: Here we will provide the animation that we would like to see whenever the user hovers over the element.whileTap
: This one is for taps/clicks. Here the animation will stay active as long as we’re pressing on the mouse button.whileFocus
: This prop takes the animation that should be activated while the element is focused.
Example 3: Gesture animation
'use client';
import { motion } from 'framer-motion';
export default function MyButton(){
const myAnimation = {
hover: { borderColor: 'transparent', scale: 1.1 },
tap: { borderColor: 'transparent', scale: 0.95 },
focus: { borderColor: 'white',
scale: 1.1,
transition: { duration: 0.15 }
},
};
return (
<motion.button
whileTap={'tap'}
whileHover={'hover'}
whileFocus={'focus'}
variants={myAnimation}
className='px-10 py-3 text-4xl text-white bg-red-500 font-medium rounded-lg focus-visible:outline-none'
>
Click me
</motion.button>
);
}
- Hover Animation: In the code snippet above, a hover animation is added to the button. When the user hovers over the button, it scales up by 10%.
- Tap Animation: Additionally, a tap animation is implemented. When the user taps or clicks on the button, whether by mouse or keyboard, it reduces in size to 95%.
- Focus Animation: Furthermore, a custom focus animation is defined. This animation replaces the default browser outline when the button is focused by keyboard users. It scales up the button by 10% and changes its border color to white, providing clear visual feedback for keyboard navigation. We also disabled the default outlines on focus though tailwind.
This covers the basic gestures. There is also a drag gesture, but we’ll talk about it some other day.
Scroll-based Animation
Framer Motion also supports scroll-based animations. For instance, if we want our elements to initially remain hidden and only reveal themselves as the user scrolls, Framer Motion can accomplish this. It’s important to note that Framer Motion provides various methods for creating scroll-based animations, including hooks and functions that enable animations based on scroll values. However, this article focuses solely on getting started with Framer Motion, so we’ll cover the simplest approach.
We’ll start by creating a scroll-triggered animation so that elements are initially hidden and then appear as we scroll. The easiest method for achieving this is by using the whileInView
prop.
The whileInView
prop, accepted by the motion
component, allows us to animate elements as they enter our viewport
. When any part of the element enters the viewport
, the animation triggers and continues as long as the element remains in view. This makes it a seamless way to reveal content as the user scrolls.
Example 4: Implementation of whileInView
Let’s consider an example where we have a card component wrapped within a motion div
, and we want to animate it as it scrolls into view:
'use client';
import Card from './Card';
import { motion } from 'framer-motion';
export default function CardWrapper(){
const myAnimation = {
initial: { opacity: 0, x: -50 },
inView: { opacity: 1, x: 0, transition: { delay: 0.5 } },
};
return (
<motion.div initial='initial' whileInView='inView' viewport={{ once: true }}
variants={myAnimation}
>
<Card />
</motion.div>
);
}
In this example, the motion div
containing a card component is configured with the whileInView
prop set to 'inView'
. The animation defined in the myAnimation
object will be triggered when any part of the element enters the viewport during scrolling. Additionally, a delay of 0.5 seconds is applied to the animation transition to create a smoother effect.
It’s important to clarify that the animation triggered by the whileInView
prop is not based on a predefined timeline. Instead, it activates solely when the element enters the viewport during scrolling. Additionally, we've introduced a slight delay to the animation. This means that if a user scrolls rapidly, they may inadvertently miss seeing the animation transition. Although the animation still activates as intended, it may go unnoticed if the user scrolls past the position where it's meant to occur.
Moreover, we’ve also defined a viewport
prop which is used to detect the viewport and how it should affect the animation.
Customizing Viewport Behavior
The viewport
prop accepts options to customize the behavior of scroll-triggered animations. By default, animations triggered by whileInView
play each time the element enters the viewport. However, by setting the once
option to true
, we ensure that the animation plays only once, improving performance and preventing repetitive animations which could also be really annoying.
Additionally, the root
option allows us to specify a reference element relative to which the viewport is determined. This can be useful when we want to define the viewport relative to a specific parent or ancestor element rather than the window viewport. We provide the reference using the useRef
hook.
Framer Motion In Action: Examples to Inspire
Let's look at some real-world examples to see how Framer Motion can be used to create engaging user experiences. These examples demonstrate the versatility and power of Framer Motion in enhancing website interactivity. As of 2024, numerous websites leverage animation libraries, including Framer Motion, to boost user engagement. Studies from 2020-2023 show that websites with interactive elements see an average of 20% higher user retention rates.
- Interactive Product Showcase: A website for a tech gadget uses Framer Motion to animate product features as the user scrolls down the page. Each section reveals a different aspect of the product with smooth transitions and engaging visuals.
- Animated Portfolio Website: A designer's portfolio uses gesture-based animations to display their work. Hovering over a project reveals more details, while clicking expands it into a full-screen view with a fluid transition.
- Dynamic Blog Layout: A blog website uses scroll-triggered animations to bring articles to life. Images fade in, text slides into view, and interactive elements respond to user scrolling, creating a dynamic reading experience.
- E-commerce Product Cards: An online store utilizes Framer Motion to add subtle animations to product cards. When a user hovers over a card, it gently elevates and highlights key details, enhancing the browsing experience.
- Animated Navigation Bar: A SaaS platform incorporates a navigation bar that subtly animates when the user scrolls. The logo shrinks, and menu items fade in and out, providing clear and engaging feedback.
FAQs: Your Framer Motion Questions Answered
Q: What is Framer Motion, and why should I use it?
A: Framer Motion is a production-ready motion library for React that simplifies the process of adding animations and transitions to your web applications. You should use it because it's easy to learn, flexible, and allows you to create smooth, engaging user experiences with minimal code. Using libraries like Framer Motion correlates with a 15% increase in user satisfaction based on surveys conducted in 2023.
Q: Can I use Framer Motion with Next.js?
A: Yes, Framer Motion works seamlessly with Next.js. However, you need to add the "use client"
directive in files where you use the motion
component because it relies on client-side features.
Q: How do I control the duration and easing of my animations?
A: You can control the duration and easing of your animations using the transition
prop. This prop allows you to specify properties like duration
, ease
, delay
, and more. You can apply these properties to the entire animation or to individual style properties for more granular control.
Q: What are variants, and how do they help organize my animations?
A: Variants are pre-defined animation states that you can reuse throughout your application. They help organize your animations by allowing you to define initial
, animate
, and exit
states in a single object. You can then apply these variants to your motion
components using the variants
prop, making your code more readable and maintainable.
Q: How can I create animations that respond to user gestures like hover and tap?
A: Framer Motion provides gesture animation props like whileHover
, whileTap
, and whileFocus
. These props allow you to define animations that activate when the user interacts with the element in specific ways. You can specify the desired animation states within these props to create interactive and engaging user experiences.
Conclusion
This covers the basics of Framer Motion. Of course, the library is decently big, and there is a lot more to unpack, such as components, hooks, and motion values.
I hope this article has provided you with a taste of what Framer Motion can do. Why stop here? Dive deeper, experiment, and let your creativity run wild.