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-motion2
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
};

