Button Ripple Effect

October 2023

import React, { MouseEvent } from "react";
type ButtonRippleEffectProps = {
variant: "neutral" | "blue" | "green" | "red";
};
const spanCn = {
neutral: "bg-neutral-100 dark:bg-neutral-600",
blue: "bg-blue-100",
green: "bg-green-100",
red: "bg-red-100",
};
const buttonCn = {
neutral:
"bg-neutral-900 text-neutral-50 dark:bg-neutral-100 dark:text-neutral-900",
blue: "bg-blue-600 text-blue-50",
green: "bg-emerald-600 text-emerald-50",
red: "bg-red-600 text-red-50",
};
export const ButtonRippleEffect: React.FC<ButtonRippleEffectProps> = ({
variant,
}) => {
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
const button = e.currentTarget;
const x = e.clientX - button.getBoundingClientRect().left;
const y = e.clientY - button.getBoundingClientRect().top;
const ripples = document.createElement("span");
ripples.style.cssText = `
left: ${x}px;
top: ${y}px;
position: absolute;
transform: translate(-50%, -50%);
pointer-events: none;
border-radius: 50%;
animation: ripple 1.4s linear infinite;
transition: 0.5s;`;
ripples.classList.add(...spanCn[variant].split(" "));
button.appendChild(ripples);
setTimeout(() => {
ripples.remove();
}, 1400);
};
return (
<>
<button
className={`relative h-8 overflow-hidden rounded-lg px-3 py-0 text-sm leading-8 ${buttonCn[variant]}`}
onClick={handleClick}
>
Go Pro
</button>
<style jsx>{`
/* you can add this to tailwind.config */
@keyframes ripple {
0% {
width: 0;
height: 0;
opacity: 0.5;
}
100% {
width: 520px;
height: 520px;
opacity: 0;
}
}
`}</style>
</>
);
};
export const ButtonRippleEffectShowcase = () => {
return (
<div className="flex flex-col gap-4 sm:flex-row">
<ButtonRippleEffect variant="neutral" />
<ButtonRippleEffect variant="blue" />
<ButtonRippleEffect variant="green" />
<ButtonRippleEffect variant="red" />
</div>
);
};
/*
tailwind.config.ts
...
extend: {
keyframes: {
ripple: {
'0%': {
width: '0',
height: '0',
opacity: '0.5',
},
'100%': {
width: '520px',
height: '520px',
opacity: '0',
},
},
},
animation: {
ripple: 'ripple 1.4s linear infinite',
},
...
usage in jsx:
...
className="animate-ripple"
...
*/