Ripple effect
Also called ink ripple or Material ripple
A circle that spreads out from the exact spot you tap or click on a button and then fades, made popular by Google's Material Design.
import { useState, type PointerEvent, type ReactNode } from 'react';
import { motion, useReducedMotion } from 'motion/react';
type Ripple = { id: number; x: number; y: number; size: number };
export function RippleButton({ children }: { children: ReactNode }) {
const [ripples, setRipples] = useState<Ripple[]>([]);
const reduceMotion = useReducedMotion();
function spawn(rect: DOMRect, x: number, y: number) {
if (reduceMotion) return;
// Big enough to reach the farthest corner from the press point.
const size =
2 * Math.hypot(Math.max(x, rect.width - x), Math.max(y, rect.height - y));
setRipples((list) => [...list, { id: performance.now(), x, y, size }]);
}
function onPointerDown(event: PointerEvent<HTMLButtonElement>) {
const rect = event.currentTarget.getBoundingClientRect();
spawn(rect, event.clientX - rect.left, event.clientY - rect.top);
}
return (
<button
type='button'
onPointerDown={onPointerDown}
onKeyDown={(event) => {
if (event.repeat || (event.key !== 'Enter' && event.key !== ' '))
return;
const rect = event.currentTarget.getBoundingClientRect();
spawn(rect, rect.width / 2, rect.height / 2);
}}
className='relative isolate overflow-hidden rounded-full bg-blue-600 px-6 py-3 text-sm font-medium text-white'
>
{ripples.map((ripple) => (
<motion.span
key={ripple.id}
aria-hidden
initial={{ scale: 0, opacity: 0.3 }}
animate={{ scale: 1, opacity: 0 }}
transition={{ duration: 0.5, ease: 'easeOut' }}
onAnimationComplete={() =>
setRipples((list) => list.filter((r) => r.id !== ripple.id))
}
className='pointer-events-none absolute rounded-full bg-white'
style={{
left: ripple.x - ripple.size / 2,
top: ripple.y - ripple.size / 2,
width: ripple.size,
height: ripple.size
}}
/>
))}
<span className='relative'>{children}</span>
</button>
);
}Add a Material-style ripple to buttons: on pointer down, spawn a circle at the exact press point, sized to reach the farthest corner, that scales from 0 to full size over 500ms with an ease-out curve while fading from 30% opacity to 0, then remove it. Clip it to the button's rounded corners, start it from the center for keyboard presses, and skip it when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Ripple effect?
A ripple is a style of press feedback. When you press a button, card, or list row, a translucent circle grows from your finger or cursor until it fills the shape, then fades away. Because it starts where you touched, it ties your action to the surface it hit.
It is the signature press style of Material Design and Android apps, so it fits interfaces that follow that look. In other design styles, a simple darken or shrink on press usually feels more at home.
Clip the ripple to the button with overflow: hidden, size the circle to reach the farthest corner, and start it from the center when the button is pressed with the keyboard. Keep the spread to about 400 to 600ms with an ease-out curve, and never make the action wait for it to finish.
Often confused with
- Press feedback
- Press feedback is any response to a press, often a slight shrink. A ripple is one specific style that spreads a circle from the press point.
Related terms
All termsPress feedback
A quick visual response, usually a slight shrink, that shows a button registered the press the moment a finger or mouse button goes down.
Origin-aware animation
A popover, menu, or tooltip that grows out of the button that opened it, by setting its transform origin on the side facing the trigger.
Micro-interaction
A small moment of feedback around a single action, like a heart that bursts when tapped or a copy icon that turns into a checkmark.
Interaction states
The set of looks a control takes as people use it, such as default, hover, pressed, focused, and disabled, each showing what will happen.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.