Ripple Press
Subtle press ripple expanding from the pointer inside any rounded child (button, card), in the current text color or primary tone, fading out quickly without blocking clicks.
minimal/effect/ripple-pressSource
"use client";
import { useRef, useState, type PointerEvent, type ReactNode } from "react";
import { cn } from "@/lib/utils";
export interface RipplePressProps {
children: ReactNode;
/** Ripple color token. */
tone?: "current" | "primary";
className?: string;
}
type Ripple = { id: number; x: number; y: number; size: number };
/** Subtle material-like ripple expanding from the press point inside its (rounded) child. Fades out, never blocks clicks. */
export function RipplePress({ children, tone = "current", className }: RipplePressProps) {
const [ripples, setRipples] = useState<Ripple[]>([]);
const next = useRef(0);
const onPointerDown = (e: PointerEvent<HTMLSpanElement>) => {
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const r = e.currentTarget.getBoundingClientRect();
const size = Math.max(r.width, r.height) * 2.2;
const id = next.current++;
setRipples((rs) => [...rs, { id, x: e.clientX - r.left - size / 2, y: e.clientY - r.top - size / 2, size }]);
window.setTimeout(() => setRipples((rs) => rs.filter((it) => it.id !== id)), 650);
};
return (
<span className={cn("relative isolate inline-flex overflow-hidden rounded-da-md", className)} onPointerDown={onPointerDown}>
{children}
<span aria-hidden className="pointer-events-none absolute inset-0 z-10">
{ripples.map((r) => (
<span
key={r.id}
className={cn("minimal-ripple absolute rounded-full", tone === "primary" ? "bg-da-primary/25" : "bg-current opacity-20")}
style={{ left: r.x, top: r.y, width: r.size, height: r.size }}
/>
))}
</span>
<style href="minimal-ripple" precedence="default">{`
@keyframes minimal-ripple { from { scale: 0; opacity: .35 } to { scale: 1; opacity: 0 } }
.minimal-ripple { animation: minimal-ripple .6s cubic-bezier(.16,1,.3,1) forwards }
`}</style>
</span>
);
}
export default RipplePress;
modules/minimal/effect/ripple-press/index.tsx
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Pressable element. |
| tone | "current" | "primary" | "current" | Ripple color. |
| className | string | — | Classes (match the child radius). |
Other micro interaction variants in Minimal
Border Beam
Card wrapper with a short primary-to-accent light beam travelling around its rounded 1px border (conic gradient + animated @property angle); always on or only on hover/focus.
Magnetic Button
Wrapper that pulls its child toward the mouse pointer on hover with a spring (inner content moves a little more for depth) and snaps back on leave.
Spotlight Card
Card micro-interaction: a soft indigo radial light follows the pointer inside the card while the 1px border brightens under the cursor. CSS variables only, no React re-render per move.
Micro interaction in other art directions
Click Burst
Micro-interaction wrapper that fires a burst of outlined square shards in DA colors from the click point (or from the center on Enter/Space), spinning outward in stepped motion.
Cursor Follower
Region where a tilted, outlined sticker label trails the mouse pointer with a springy lag and pops in/out on enter/leave. Mouse only; add cursor-none on the region to replace the cursor.
Shake Feedback
Error micro-interaction wrapper: shakes its content horizontally in hard steps and flashes a thick danger outline each time shakeKey changes (wrong password, invalid code). Children keep their state.
Stack Hover
Micro-interaction wrapper: colored slabs hidden behind a card or button fan out diagonally on hover and keyboard focus, in stepped motion, like a stack of printed sheets. Pure CSS.
Glare Card
Glass card where a soft specular glare and a luminous primary rim follow the mouse pointer (CSS variables, masked border), like light sliding over real glass.
Gradient Border
Highlight wrapper with a rotating conic-gradient border (primary → accent → pink) and optional soft glow around a frosted inner surface. Pure CSS via a registered @property angle.
Liquid Button
Frosted pill button that fills with a wavy primary→accent liquid rising from the bottom on hover or keyboard focus while the label turns white. Pure CSS.
Tilt Card
Frosted card that tilts in 3D toward the pointer on a spring while a specular glare slides across the glass; eases back flat on leave. Motion values only, no re-render per move.
Copy Email
Big email address that copies itself on click: the address swaps to “Copied to clipboard” with a signal dot for 1.8s via a vertical slide; announced to screen readers.
Cursor Label
Hover area where a small ink pill with a mono label (“View ↗”) follows the pointer with slight lag; the native cursor stays visible. Mouse only; nothing on touch.
Invert Hover
Row/button whose ink fill wipes in from the left on hover or focus while the text inverts (mix-blend-difference) — the signature interaction for index lists.
Square Switch
Square toggle: a hairline rectangle with a square knob that snaps across with the emphasized ease, filling ink when on; mono ON/OFF state label; role=switch.
Copy Feedback
Copyable mono field (API key, IBAN, invoice link): click copies, the icon cross-fades to a green check and a “Copied” tooltip pops for 1.6s; announced to screen readers.
Press Ripple
Button with a restrained material-style ripple: a soft circle expands from the press point and fades, plus a 1px press-down; disabled with reduced motion.
Spotlight Border
Card whose 1px border lights up in primary around the pointer (a radial highlight follows the cursor along the edge) with a faint inner glow; plain bordered card on touch.
Toggle Save
Settings row with an auto-saving switch: the knob slides, an inline status shows a spinner “Saving…” then a green “Saved” check that fades after 2s (aria-live).
Breathe Button
Calm primary CTA that slowly “breathes”: a soft sage halo expands and fades around the pill every few seconds; pauses on hover and with reduced motion. Pure CSS.
Leaf Like
Appreciation button: pressing fills the leaf with sage, bumps it with a soft overshoot and releases three small leaves that float up and fade; counter updates.
Sprout Progress
Progress bar with a plant riding the fill: a rounded sage track whose leading edge carries a sprout that grows leaves at 33% and 66% and blooms at 100%.
Water Ripple
Surface that answers a tap like still water: three concentric sage rings spread from the pointer and fade. Wrap any card or panel.
Check Burst
Satisfying task checkbox: the round box fills mint with a bouncy check and a ring of pastel dots bursts outward when ticked; the label strikes through.
Heart Like
Like button: the heart pops with a springy scale, fills red and throws a ring of tiny hearts; the count ticks and the pill tints.
Hover Lift
Card wrapper that lifts, tilts a couple of degrees and grows a soft wide shadow on hover or keyboard focus-within, with a springy ease.
Squish Button
Chunky “gummy” pill button with a flat darker bottom lip that squishes down (scales wider/shorter, lip disappears) when pressed and springs back. CSS only.