Skip to main content

Live demo

Bounce animations simulate elastic, spring-like motion that creates a playful, energetic feel. They’re perfect for drawing attention, celebrating actions, and adding personality to your interface.
Bounce animations work best with spring physics for natural motion or carefully crafted easing curves.

Complete code example

import { motion } from 'framer-motion'

export default function BounceDemo() {
  return (
    <div className="space-y-8">
      {/* Vertical bounce */}
      <motion.div
        animate={{
          y: [0, -50, 0],
          scale: [1, 0.9, 1]
        }}
        transition={{
          duration: 0.8,
          repeat: Infinity,
          repeatType: 'reverse',
          ease: 'easeOut'
        }}
        className="w-24 h-24 bg-blue-500 rounded-lg mx-auto"
      />

      {/* Spring bounce on click */}
      <motion.button
        whileTap={{
          scale: 0.9,
          y: 5
        }}
        transition={{
          type: 'spring',
          stiffness: 400,
          damping: 10
        }}
        className="px-6 py-3 bg-purple-500 text-white rounded-lg"
      >
        Bounce on click
      </motion.button>
    </div>
  )
}

How it works

Bounce animations simulate elastic motion:
1

Define motion path

Set keyframes for the bounce trajectory, typically using Y-axis translation.
2

Add squash and stretch

Include subtle scale changes to enhance the bouncing effect.
3

Apply easing

Use ease-out for natural deceleration or spring physics for elastic bounce.

Bounce types

Vertical bounce

Classic up-and-down bouncing motion

Scale bounce

Growing and shrinking for pulsing effect

Elastic bounce

Overshoot and settle with spring physics

Multiple bounces

Decreasing amplitude for realistic physics

Variations

Realistic bounce

Multiple bounces with decreasing height:
import { motion } from 'framer-motion'

function RealisticBounce() {
  return (
    <motion.div
      animate={{
        y: [0, -100, 0, -60, 0, -30, 0, -10, 0]
      }}
      transition={{
        duration: 2,
        times: [0, 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
        ease: 'easeOut'
      }}
      className="w-16 h-16 bg-blue-500 rounded-full"
    />
  )
}

Button bounce feedback

Bounce on user interaction:
import { motion } from 'framer-motion'

function BounceButton() {
  return (
    <motion.button
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.9 }}
      animate={{ y: [0, -5, 0] }}
      transition={{
        y: {
          duration: 0.5,
          repeat: Infinity,
          repeatType: 'reverse',
          ease: 'easeInOut'
        }
      }}
      className="px-6 py-3 bg-green-500 text-white rounded-lg"
    >
      Bouncing CTA
    </motion.button>
  )
}

Loading bounce

Three dots bouncing in sequence:
import { motion } from 'framer-motion'

function LoadingDots() {
  const bounceTransition = {
    duration: 0.5,
    repeat: Infinity,
    repeatType: 'reverse' as const,
    ease: 'easeOut'
  }

  return (
    <div className="flex gap-2">
      <motion.div
        animate={{ y: [0, -20, 0] }}
        transition={{ ...bounceTransition, delay: 0 }}
        className="w-4 h-4 bg-blue-500 rounded-full"
      />
      <motion.div
        animate={{ y: [0, -20, 0] }}
        transition={{ ...bounceTransition, delay: 0.15 }}
        className="w-4 h-4 bg-blue-500 rounded-full"
      />
      <motion.div
        animate={{ y: [0, -20, 0] }}
        transition={{ ...bounceTransition, delay: 0.3 }}
        className="w-4 h-4 bg-blue-500 rounded-full"
      />
    </div>
  )
}

Elastic entrance

Spring-based bounce for entrances:
import { motion } from 'framer-motion'

function ElasticEntrance() {
  return (
    <motion.div
      initial={{ scale: 0, y: 100 }}
      animate={{ scale: 1, y: 0 }}
      transition={{
        type: 'spring',
        stiffness: 260,
        damping: 10
      }}
      className="p-6 bg-purple-500 text-white rounded-lg"
    >
      I bounce in!
    </motion.div>
  )
}

Example from the playground

From the CSSAnimations component:
const presets = {
  bounce: `
.animated-element {
  width: 100px;
  height: 100px;
  background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  animation: bounce 2s infinite;
}

@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-50px); }
}`,
}

Best practices

Spring-based bounces feel more natural than keyframe animations.
// Natural spring bounce
transition={{ type: 'spring', stiffness: 300, damping: 10 }}

// Less natural keyframe
transition={{ duration: 0.5, ease: 'easeOut' }}
Subtle scale changes during bounce enhance the effect.
animate={{
  y: [0, -50, 0],
  scaleY: [1, 0.9, 1],  // Squash on impact
  scaleX: [1, 1.1, 1]   // Stretch horizontally
}}
Bounce animations are attention-grabbing. Use them sparingly for important actions or feedback.
Playful bounces work great for casual apps but may not suit professional or serious contexts.

Common use cases

  • Loading indicators
  • Success confirmations
  • Call-to-action buttons
  • Notification badges
  • Game elements
  • Playful micro-interactions
  • Error shake (horizontal bounce)
  • Scroll-to-top buttons

Performance tips

Use transform properties for bouncing. Avoid animating top, bottom, or margin as they cause layout recalculations.
// Good - GPU accelerated
<motion.div animate={{ y: -50 }} />

// Bad - causes layout recalc
<motion.div animate={{ marginTop: -50 }} />

Advanced: Physics-based bounce

Create realistic physics with decreasing amplitude:
import { motion } from 'framer-motion'

function PhysicsBounce() {
  return (
    <motion.div
      animate={{
        y: [0, -120, 0, -80, 0, -40, 0, -20, 0, -5, 0]
      }}
      transition={{
        duration: 3,
        times: [0, 0.15, 0.3, 0.45, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 1],
        ease: 'linear'
      }}
      className="w-20 h-20 bg-red-500 rounded-full"
    />
  )
}

Scale

Grow and shrink animations

Pulse

Rhythmic pulsing effects

Rotate

Spinning animations

Build docs developers (and LLMs) love