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
Framer Motion
React Spring
CSS
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 >
)
}
import { useSpring , animated } from '@react-spring/web'
import { useState } from 'react'
export default function BounceDemo () {
const [ trigger , setTrigger ] = useState ( false )
const bounceProps = useSpring ({
transform: trigger
? 'translateY(-50px) scale(0.9)'
: 'translateY(0px) scale(1)' ,
config: {
tension: 300 ,
friction: 10
}
})
return (
< div >
< animated.div
style = { {
... bounceProps ,
width: '6rem' ,
height: '6rem' ,
background: '#8B5CF6' ,
borderRadius: '0.5rem' ,
margin: '0 auto' ,
cursor: 'pointer'
} }
onClick = { () => setTrigger ( ! trigger ) }
/>
</ div >
)
}
import './bounce.css'
export default function BounceDemo () {
return (
< div className = "space-y-8" >
< div className = "bounce-vertical w-24 h-24 bg-blue-500 rounded-lg mx-auto" />
< div className = "bounce-scale w-24 h-24 bg-purple-500 rounded-full mx-auto" />
</ div >
)
}
@keyframes bounce {
0% , 100% {
transform : translateY ( 0 );
}
50% {
transform : translateY ( -50 px );
}
}
@keyframes bounce-scale {
0% {
transform : scale ( 1 );
}
50% {
transform : scale ( 1.2 );
}
100% {
transform : scale ( 1 );
}
}
.bounce-vertical {
animation : bounce 0.8 s ease-out infinite ;
}
.bounce-scale {
animation : bounce-scale 1 s ease-in-out infinite ;
}
How it works
Bounce animations simulate elastic motion:
Define motion path
Set keyframes for the bounce trajectory, typically using Y-axis translation.
Add squash and stretch
Include subtle scale changes to enhance the bouncing effect.
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"
/>
)
}
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
Use spring physics for realism
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
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