Ripple Button
Ripple Button listens for pointerdown, measures where the press landed inside the button, and spawns a circle at that point. Each circle grows to six times its size while fading to nothing, then removes itself from the list.
Ripples are independent, so pressing quickly in several places leaves several circles spreading at once. Presses are ignored entirely when the visitor has asked for reduced motion.
Usage
Each press spawns a circle at the pointer that spreads to six times its size and fades out.
<template>
<div class="flex w-full flex-col items-center gap-4 py-6">
<MRippleButton>
Click anywhere
</MRippleButton>
</div>
</template>
Customize
Customize
Props
| Prop | Type | Default | Description |
|---|---|---|---|
duration | number | 0.7 | Seconds a ripple takes to spread out and fade. The ripple is dropped from the list once this elapses. |
class | string | '' | CSS classes for the button itself. |
Slots
| Slot | Props | Description |
|---|---|---|
default | - | The button's label, drawn above the ripples. |
UI
This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.rippleButton in app.config.ts.
| Prop | Type | Default | Description |
|---|---|---|---|
ui | object | - | Per-slot classes merged over the theme defaults. |
| Slot | Props | Description |
|---|---|---|
root | - | relative inline-flex items-center justify-center overflow-hidden rounded-lg border border-default bg-elevated px-6 py-3 text-sm font-medium text-highlighted transition active:scale-[0.98] |
ripple | - | pointer-events-none absolute size-8 rounded-full bg-primary/40 |
label | - | relative z-10 |
Accessibility
The root is a real <button type="button">, so keyboard activation and the focus ring are unchanged. The ripple only reacts to pointerdown; a keyboard press gets the normal button feedback and no ripple, which is intentional — the ripple marks where a pointer landed, and a keyboard press has no such point.