Bounce Animation
Create lively effects that make elements appear to bounce
Bounce Animation
The Bounce animation creates a bouncing effect that makes elements appear to spring up and down. It's effective for drawing attention and creating playful, engaging user experiences.
Basic Usage
import { transition } from '@ssgoi/react';
import { bounce } from '@ssgoi/react/transitions';
function Component() {
const [isVisible, setIsVisible] = useState(true);
return (
<div>
{isVisible && (
<div ref={transition({ key: 'bounce-element', ...bounce() })}>
Element with bounce animation
</div>
)}
</div>
);
}
Options
interface BounceOptions {
height?: number; // Bounce height (default: 20)
intensity?: number; // Bounce intensity (default: 1)
scale?: boolean; // Add scale effect (default: true)
fade?: boolean; // Add fade effect (default: false)
direction?: 'up' | 'down'; // Bounce direction (default: 'up')
spring?: {
stiffness?: number; // Spring stiffness (default: 800)
damping?: number; // Damping coefficient (default: 15)
};
}
Option Details
- height: Maximum bounce height (pixels)
- intensity: Bounce count and intensity (1 = default, 2 = double)
- scale: Add scaling effect with bounce
- fade: Add fade effect with bounce
- direction: Bounce direction
'up'
: Bounce upward'down'
: Drop downward
- spring: Spring physics settings (higher stiffness = faster bounce)
Usage Examples
Bounce Intensity Control
// Soft bounce
const softBounce = bounce({
height: 10,
intensity: 0.5,
spring: { stiffness: 600, damping: 20 }
});
// Strong bounce
const strongBounce = bounce({
height: 30,
intensity: 2,
spring: { stiffness: 1000, damping: 10 }
});
// Subtle bounce
const subtleBounce = bounce({
height: 5,
intensity: 0.3
});
Direction Change
// Bounce up (default)
const bounceUp = bounce({
direction: 'up'
});
// Bounce down (dropping effect)
const bounceDown = bounce({
direction: 'down',
height: 25
});
Combined Effects
// Bounce + Fade
const bounceFade = bounce({
fade: true,
height: 20
});
// Bounce only (no scale)
const bounceOnly = bounce({
scale: false,
height: 15
});
// All effects combined
const bounceAll = bounce({
height: 25,
intensity: 1.5,
scale: true,
fade: true,
spring: { stiffness: 700, damping: 12 }
});
Practical Use Cases
Like Button
function LikeButton() {
const [isLiked, setIsLiked] = useState(false);
return (
<button
onClick={() => setIsLiked(!isLiked)}
className="relative p-2"
>
{isLiked ? (
<HeartIcon
ref={transition({
key: 'heart-filled',
...bounce({
height: 15,
intensity: 1.2,
spring: { stiffness: 900, damping: 15 }
})
})}
className="w-8 h-8 text-red-500"
/>
) : (
<HeartOutlineIcon className="w-8 h-8 text-gray-400" />
)}
{/* Like count animation */}
{isLiked && (
<span
ref={transition({
key: 'like-count',
...bounce({
height: 10,
direction: 'up',
fade: true
})
})}
className="absolute -top-2 -right-2 text-xs text-red-500"
>
+1
</span>
)}
</button>
);
}
Notification Bell
function NotificationBell({ hasNew }) {
return (
<div className="relative">
<BellIcon
ref={hasNew ? transition({
key: 'bell-bounce',
...bounce({
height: 8,
intensity: 2,
spring: { stiffness: 1200, damping: 20 }
})
}) : undefined}
className="w-6 h-6"
/>
{hasNew && (
<div
ref={transition({
key: 'notification-dot',
...bounce({
height: 5,
scale: true
})
})}
className="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full"
/>
)}
</div>
);
}
Success Message
function SuccessMessage({ show, message }) {
return (
<>
{show && (
<div
ref={transition({
key: 'success-message',
...bounce({
height: 20,
direction: 'down',
fade: true,
spring: { stiffness: 600, damping: 18 }
})
})}
className="fixed top-4 left-1/2 -translate-x-1/2 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg flex items-center gap-2"
>
<CheckCircleIcon className="w-5 h-5" />
{message}
</div>
)}
</>
);
}
Drop Animation
function DroppableItem({ item, onDrop }) {
const [isDragging, setIsDragging] = useState(false);
const [isDropped, setIsDropped] = useState(false);
const handleDrop = () => {
setIsDropped(true);
onDrop(item);
};
return (
<div
draggable
onDragStart={() => setIsDragging(true)}
onDragEnd={() => {
setIsDragging(false);
handleDrop();
}}
className={isDragging ? 'opacity-50' : ''}
>
{isDropped ? (
<div
ref={transition({
key: 'dropped-item',
...bounce({
height: 30,
direction: 'down',
intensity: 1.5,
spring: { stiffness: 500, damping: 12 }
})
})}
className="p-4 bg-blue-100 rounded-lg"
>
{item.name} (Dropped!)
</div>
) : (
<div className="p-4 bg-gray-100 rounded-lg cursor-move">
{item.name}
</div>
)}
</div>
);
}
Advanced Usage
Continuous Bounce
function ContinuousBounce() {
const [bounceCount, setBounceCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setBounceCount(c => c + 1);
}, 2000);
return () => clearInterval(interval);
}, []);
return (
<div
ref={transition({
key: `bounce-${bounceCount}`,
...bounce({
height: 15,
intensity: 0.8
})
})}
className="w-20 h-20 bg-purple-500 rounded-full"
/>
);
}
Elastic Menu
function ElasticMenu({ items }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="relative">
<button
onClick={() => setIsOpen(!isOpen)}
className="p-3 bg-blue-500 text-white rounded-full"
>
<MenuIcon />
</button>
{isOpen && (
<div className="absolute top-full mt-2 space-y-2">
{items.map((item, index) => (
<button
key={item.id}
ref={transition({
key: `menu-item-${item.id}`,
...bounce({
height: 20 - index * 3, // Progressively decrease
intensity: 1,
spring: {
stiffness: 800 - index * 50, // Sequential effect
damping: 15
}
})
})}
className="block w-full px-4 py-2 bg-white rounded-lg shadow hover:bg-gray-50"
style={{
transitionDelay: `${index * 50}ms` // Stagger effect
}}
>
{item.label}
</button>
))}
</div>
)}
</div>
);
}
Ball Bounce Simulation
function BouncingBall() {
const [position, setPosition] = useState({ x: 50, y: 0 });
const [bounceKey, setBounceKey] = useState(0);
const handleClick = (e) => {
const rect = e.currentTarget.getBoundingClientRect();
setPosition({
x: e.clientX - rect.left,
y: e.clientY - rect.top
});
setBounceKey(k => k + 1);
};
return (
<div
className="relative w-full h-96 bg-gray-100 overflow-hidden"
onClick={handleClick}
>
<div
ref={transition({
key: `ball-${bounceKey}`,
...bounce({
height: 150,
direction: 'down',
intensity: 2,
scale: true,
spring: { stiffness: 400, damping: 10 }
})
})}
className="absolute w-12 h-12 bg-red-500 rounded-full"
style={{
left: position.x - 24,
top: position.y - 24
}}
/>
</div>
);
}
Performance Optimization
- Bounce uses
transform: translateY()
for GPU acceleration - Higher
intensity
values require more calculations - Consider performance when bouncing multiple elements simultaneously
Performance Tips
// Mobile optimization
const isMobile = window.innerWidth < 768;
const optimizedBounce = bounce({
height: isMobile ? 10 : 20,
intensity: isMobile ? 0.8 : 1,
spring: {
stiffness: isMobile ? 900 : 800,
damping: 15
}
});
Accessibility Considerations
<button
ref={transition({
key: 'accessible-bounce',
...bounce()
})}
aria-label="New notification available"
aria-live="polite"
aria-atomic="true"
>
<NotificationIcon />
</button>
Recommended Use Cases
- Interaction feedback: Button clicks, likes
- Notifications: New messages, update alerts
- Success/Complete states: Task completion indicators
- Game elements: Score gains, item collection
- Tutorials: Highlighting important elements