Create an Animated Scaling Button using Framer Motion (Motion for React)

Mary OjoMary Ojo
3 min read

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:

  1. Wrap the button component with a motion.div element instead of directly applying motion to the button element to separate it’s styling.

  2. 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 styling

    • hover: The state where the button scales up and adds shadow on hover

    • tap: In this state, the button slightly scales down when clicked/tapped

  3. 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 bounce

      For 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)

0
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