Ripple Button
FREE
An interactive button component with a beautiful ripple effect animation on click.
Demo
Exclusive Launch 50% offspots left: 0 / 50


$39.99
$19.99
Payment once and get lifetime access
Access to all animations
All updates
All animations
No subscriptions
Installation
1
Install framer-motion
pnpm add framer-motion
2
Copy and paste the following component into your project:
Add this component RippleButton.tsx to your project.
"use client";
import { motion } from "framer-motion";
import React, { useState, useEffect, useRef } from "react";
const RippleButton = () => {
const [ripples, setRipples] = useState<
{
id: number;
x: number;
y: number;
size: number;
}[]
>([]);
// Track timeout IDs to clear them on unmount
const timeoutRefs = useRef<NodeJS.Timeout[]>([]);
// Clear all pending timeouts on component unmount
useEffect(() => {
return () => {
timeoutRefs.current.forEach((timeout) => clearTimeout(timeout));
};
}, []);
const createRipple = (e: React.MouseEvent<HTMLButtonElement>) => {
const button = e.currentTarget as HTMLButtonElement;
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = e.clientX - rect.left - size / 2;
const y = e.clientY - rect.top - size / 2;
const newRipple = {
x,
y,
size,
id: Date.now(),
};
setRipples((prev) => [...prev, newRipple]);
// Store timeout ID and clear it from the ref when it executes
const timeoutId = setTimeout(() => {
setRipples((prev) => prev.filter((ripple) => ripple.id !== newRipple.id));
// Remove this timeout from the ref array
timeoutRefs.current = timeoutRefs.current.filter(
(id) => id !== timeoutId,
);
}, 600);
// Add timeout ID to ref for cleanup
timeoutRefs.current.push(timeoutId);
};
return (
<button
className="relative overflow-hidden rounded-lg bg-white px-6 py-3 text-black"
onClick={createRipple}
>
<span className="relative z-10">Click for Ripple</span>
{ripples.map((ripple) => (
<motion.span
key={ripple.id}
className="pointer-events-none absolute rounded-full bg-black opacity-20"
style={{
left: ripple.x,
top: ripple.y,
width: ripple.size,
height: ripple.size,
}}
initial={{ scale: 0, opacity: 0.3 }}
animate={{ scale: 2, opacity: 0 }}
transition={{ duration: 0.6 }}
/>
))}
</button>
);
};
export default RippleButton;
3
Start using the ripple button in your components.
Usage Example
Customization
You can customize the RippleButton by modifying the component code:
// Custom styling example
<button
className="relative overflow-hidden rounded-lg bg-blue-500 px-8 py-4 text-white font-semibold hover:bg-blue-600 transition-colors"
onClick={createRipple}
>
<span className="relative z-10">Custom Button</span>
{ripples.map((ripple) => (
<motion.span
key={ripple.id}
className="pointer-events-none absolute rounded-full bg-white opacity-30"
style={{
left: ripple.x,
top: ripple.y,
width: ripple.size,
height: ripple.size,
}}
initial={{ scale: 0, opacity: 0.3 }}
animate={{ scale: 2, opacity: 0 }}
transition={{ duration: 0.6 }}
/>
))}
</button>
Features
- Interactive Ripple Effect: Creates a ripple animation at the click position
- Multiple Ripples: Supports multiple simultaneous ripples
- Automatic Cleanup: Ripples are automatically removed after animation
- Customizable: Easy to modify colors, size, and styling
- Smooth Animation: Uses Framer Motion for smooth transitions
- Responsive: Works on all screen sizes
Properties
The current RippleButton
component is self-contained and doesn't accept props. However, you can easily extend it to accept custom props:
Property | Type | Default | Description |
---|---|---|---|
children | ReactNode | "Click for Ripple" | Button text content |
className | string | "" | Additional CSS classes |
rippleColor | string | "bg-black" | Color of the ripple effect |
rippleOpacity | number | 0.2 | Opacity of the ripple effect |
duration | number | 0.6 | Duration of the ripple animation |
onClick | function | - | Additional click handler |
Advanced Usage
For more control over the ripple effect, you can create a customizable version:
interface RippleButtonProps {
children: React.ReactNode;
className?: string;
rippleColor?: string;
rippleOpacity?: number;
duration?: number;
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
}
const CustomizableRippleButton: React.FC<RippleButtonProps> = ({
children,
className = "",
rippleColor = "bg-black",
rippleOpacity = 0.2,
duration = 0.6,
onClick,
}) => {
// ... component implementation
};