Create an Animated Scaling Button using Framer Motion (Motion for React)
Difficulty: ⭐️ (1/5 stars)
Setup/Prerequisites: React.js, TailwindCSS, Framer Motion
Key Concepts: Using animate, whileHover, whileTap and variants in Framer Motion
The Challenge
Since today is day 1, I’m starting with a simple animation - a button that scales on hover and tap. This animation is quite simple but shows core Framer Motion concepts like variants and gesture animations.
Key Animation Features
Smooth scale animation on hover
Slight scale reduction on click/tap
Subtle shadow animation
Spring animation for natural movement
Some things you should take note of in these highlighted features are the italicized words and that’s because animations work best when they are used just in the right amount and in the right places - they should feel natural🤗
Code Breakdown
1. Implementation Details
The button is created first before going on to implement the different states and adding animations.
The animation happens in three main steps:
Wrap the button component with a
motion.div
element instead of directly applying motion to the button element to separate it’s styling.Identify the states. Looking at the key animation features, there are 3 defined states I could get. The
buttonVariants
object is where the states are defined:initial
: The button's default state and stylinghover
: The state where the button scales up and adds shadow on hovertap
: In this state, the button slightly scales down when clicked/tapped
Specifying the transition type: This defines how the button changes from one state to another. Here I’m using the spring transition which creates a bouncy, natural feel. The other properties related to the ‘spring’ transition are also set to properly add the mild transition effect.
stiffness: 400
makes the animation “snap“The value here usually ranges from 0 to 1000, with higher values making the animation more rigid, while lower values make it softer and slower.
damping: 10
This adds a slight bounceFor damping the value ranges from 0 to 100, with higher values make the animation settle faster, while lower values create more bounce.
2. Coding the Animated Button
import { motion } from "framer-motion";
export default function AnimatedButton() {
return (
<div className="flex min-h-screen items-center justify-center bg-gray-100">
<motion.div
variants={buttonVariants}
initial="initial"
whileHover="hover"
whileTap="tap"
>
<button className="bg-blue-500 px-6 py-2 text-white">
Hover Me
</button>
</motion.div>
</div>
);
}
3. Defining the Animations Using Code
In the buttonVariants
object, the different states which have been previously identified are defined using the styling specific to each state.
💡Remember to use subtle shadows
const buttonVariants = {
initial: {
scale: 1,
boxShadow: "0px 0px 0px rgba(0,0,0,0.2)",
},
hover: {
scale: 1.1,
boxShadow: "0px 5px 15px rgba(0,0,0,0.2)",
transition: {
type: "spring",
stiffness: 400,
damping: 10
}
},
tap: {
scale: 0.95,
boxShadow: "0px 2px 5px rgba(0,0,0,0.2)",
}
};
Live Demo
Key Takeaways
Spring animations feel more natural than linear ones like for interface elements.
Small scale changes (like 0.95-1.1) are often more realistic.
Combining scale with mild shadow creates a great three-dimensional effect.
Resources Used
Ideas for Enhancement ✨
What animation ideas do you suggest I add to this button? I’m thinking of these:
Adding sound effects for interaction
Creating different variants for different button states (loading, success and error)
Subscribe to my newsletter
Read articles from Mary Ojo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Mary Ojo
Mary Ojo
Design Engineer | WTM Ambassador