Ripple Button
A button with a spreading click ripple, radiating a Material-style wave out from the click point.
On click, a ripple radiates from the cursor's landing point, with a diameter reaching the farthest corner so the wave always covers the whole button. The ripple sits beneath the content and is clipped into the button's shape by overflow-hidden.
Loading preview…
npx shadcn@latest add https://webberui.com/r/ripple-button.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
0.6
0.5
<RippleButton />
Installation
npx shadcn@latest add https://webberui.com/r/ripple-button.jsonOr, once registries are configured in components.json, install it as @webberui/ripple-button.
Usage
import { RippleButton } from "@/components/ui/ripple-button";
<RippleButton onClick={() => console.log("clicked")}>
Click to ripple
</RippleButton>To change the color just pass rippleColor; all other <button> attributes (type, disabled, onClick, and so on) are forwarded.
Props
Apart from the props below, all native <button> attributes are forwarded.
| Prop | Type | Default | Description |
|---|---|---|---|
rippleColor | string | "rgba(255, 255, 255, 0.55)" | Ripple color; any CSS color value |
duration | number | 0.6 | Duration of a single ripple's spread (seconds) |
opacity | number | 0.5 | Starting opacity of the ripple |
className | string | — | Forwarded to the button; can override the default styles |
children | ReactNode | — | Button content |
Accessibility
- When the user has "reduce motion" enabled at the system level, the ripple is skipped and only the ordinary button behavior remains
- The ripple layer carries
aria-hiddenandpointer-events-none, so it affects neither assistive technology nor clicks - The native
<button>semantics and keyboard focus ring are preserved, and interaction is disabled whiledisabled