Ripple Effect
Ripple effect is a modern animation component designed to enrich user interaction by creating a dynamic ripple effect when clicking on buttons or any HTML element. Built with Tailwind CSS and Motion.
import { RippleEffect } from "@/components/core/ripple-effect";
import { Button } from "@/components/ui/button";
export default function RippleEffectButton() {
return (
<RippleEffect className="rounded-lg">
<Button size="lg">Click me</Button>
</RippleEffect>
);
}
Installation
Install the following dependencies:
npm install motion
Copy and paste the following code into your project:
"use client";
import React from "react";
import { motion, AnimatePresence } from "motion/react";
interface RippleProps {
children: React.ReactNode;
color?: string;
duration?: number;
className?: string;
}
interface RipplePosition {
x: number;
y: number;
size: number;
id: number;
}
export const RippleEffect = ({
children,
color = "rgba(255, 255, 255, 0.7)",
duration = 0.8,
className,
}: RippleProps) => {
const [ripples, setRipples] = React.useState<RipplePosition[]>([]);
const containerRef = React.useRef<HTMLDivElement>(null);
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const size = Math.max(rect.width, rect.height);
const newRipple: RipplePosition = {
x,
y,
size: size * 2,
id: Date.now(),
};
setRipples((prevRipples) => [...prevRipples, newRipple]);
setTimeout(() => {
setRipples((prevRipples) =>
prevRipples.filter((ripple) => ripple.id !== newRipple.id),
);
}, duration * 1000);
};
return (
<div
ref={containerRef}
className={`inline-flex relative overflow-hidden rounded-lg ${className}`}
onMouseDown={handleClick}
>
{children}
<AnimatePresence>
{ripples.map((ripple) => (
<motion.div
key={ripple.id}
initial={{
width: 0,
height: 0,
x: ripple.x,
y: ripple.y,
opacity: 0.5,
borderRadius: "100%",
}}
animate={{
width: ripple.size,
height: ripple.size,
x: ripple.x - ripple.size / 2,
y: ripple.y - ripple.size / 2,
opacity: 0,
borderRadius: "100%",
}}
exit={{ opacity: 0 }}
transition={{ duration, ease: "easeOut" }}
style={{
position: "absolute",
backgroundColor: color,
pointerEvents: "none",
}}
/>
))}
</AnimatePresence>
</div>
);
};
Update the import paths to match your project setup.
Usage
import { RippleEffect } from "@/components/core/ripple-effect";
import { Button } from "@/components/ui/button";
export default function RippleEffectButton() {
return (
<RippleEffect className="rounded-lg">
<Button size="lg">Click me</Button>
</RippleEffect>
);
}
Examples
Colored
Blue
Green
Purple
Red
import { RippleEffect } from "@/components/core/ripple-effect";
export default function RippleEffectColored() {
return (
<div className="grid grid-cols-2 gap-4">
<div>
<RippleEffect className="block" color="var(--color-blue-400)">
<div className="w-36 bg-blue-200 p-2 text-center text-blue-800">Blue</div>
</RippleEffect>
</div>
<div>
<RippleEffect className="block" color="var(--color-green-400)">
<div className="w-36 bg-green-200 p-2 text-center text-green-800">Green</div>
</RippleEffect>
</div>
<div>
<RippleEffect className="block" color="var(--color-purple-400)">
<div className="w-36 bg-purple-200 p-2 text-center text-purple-800">Purple</div>
</RippleEffect>
</div>
<div>
<RippleEffect className="block" color="var(--color-red-400)">
<div className="w-36 bg-red-200 p-2 text-center text-red-800">Red</div>
</RippleEffect>
</div>
</div>
);
}
Image


import Image from "next/image";
import { RippleEffect } from "@/components/core/ripple-effect";
export default function RippleEffectImage() {
return (
<div className="flex gap-4">
<RippleEffect color="var(--color-black)">
<figure className="relative aspect-square w-40">
<Image
src="https://bundui-images.netlify.app/products/06.jpeg"
fill
alt="ripple effect image"
/>
</figure>
</RippleEffect>
<RippleEffect color="var(--color-purple-600)">
<figure className="relative aspect-square w-40">
<Image
src="https://bundui-images.netlify.app/products/07.jpeg"
fill
alt="ripple effect image"
/>
</figure>
</RippleEffect>
</div>
);
}
Props
Prop | Type | Default |
---|---|---|
className? | string | - |
duration? | number | 0.8 |
color? | string | "rgba(255, 255, 255, 0.7)" |
children | React.ReactNode | - |
Marquee Effect
Add dynamic movement to your UI with Marquee effect, ideal for highlighting important information with smooth, continuous scrolling. Built with Tailwind CSS and Motion.
Scroll Progress Bar
The scroll progress bar adds a dynamic, interactive scrolling indicator, built with Motion and Tailwind CSS, enhancing user experience with smooth transitions.