GitHub

Ripple

Concentric expanding ripples for radar-like, soft indeterminate progress.

Loading...
import { Ripple } from "@/components/loading-ui/ripple";

export function RippleDemo() {

Installation

pnpm dlx shadcn@latest add @loading-ui/ripple

Usage

import { Ripple } from "@/components/loading-ui/ripple";
<Ripple />

Customization

Ripple is an SVG with two staggered circles: each ring grows and fades using SMIL animation. Color follows currentColor on the strokes, and the overall scale comes from size-* on the root.

Size

Ripples read best with a little breathing room—step from compact inline sizes up to hero-style empty states.

Loading...Loading...Loading...Loading...
import { Ripple } from "@/components/loading-ui/ripple";

export function RippleSize() {

Color

Tint with text utilities so the waves match primary actions, muted chrome, or brand accents.

Loading...Loading...Loading...
import { Ripple } from "@/components/loading-ui/ripple";

export function RippleColor() {

Ring weight

The group defaults to a medium stroke; narrow or embolden both rings together with a descendant selector on the <g>.

Loading...Loading...Loading...
import { Ripple } from "@/components/loading-ui/ripple";

export function RippleRingWeight() {

Animation cadence

Expansion and fade timings are defined on the SVG <animate> elements (dur, keySplines, and the negative begin offset on the second ring). To change the rhythm, edit those values in ripple.tsx—they are not driven by Tailwind animation-duration utilities.

Examples

Button

Keeps toolbar and form actions feeling “alive” while a background sweep runs.

import { Button } from "@/components/ui/button";
import { Ripple } from "@/components/loading-ui/ripple";

Badge

Works in compact status chips where a full spinner would feel heavy.

Loading...SonarLoading...Radar pingLoading...Wake scan
import { Badge } from "@/components/ui/badge";
import { Ripple } from "@/components/loading-ui/ripple";

Alert

Pair with honest copy when you want to signal active scanning rather than a hard error.

import { Button } from "@/components/ui/button";
import {
  Alert,

Empty

Ripples naturally occupy the focal point of an empty illustration slot.

Loading...

Widening the search

Each ring is a soft ping into your data—great when you want motion that feels expansive rather than frantic.

import { Button } from "@/components/ui/button";
import {
  Empty,