Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Backgrounds

Pro

Ripple Background for React

Concentric rings around the centre that breathe in and out, one after another, out past the edges. For React with Base UI, when a logo, an avatar or a short headline needs a calm, living stage.

Framework

Concentric rings around the centre breathe in and out, each a moment after the one inside it, so a soft pulse runs outward. The rings spread from a small one in the middle to past the container's corners, each a thin rim with a fill that deepens toward it, so the middle is the brightest and the rings fade as they go, melting into the page. It makes a good stage for a logo, an avatar or a short headline. It's pure CSS: one keyframe scales each ring, delayed by its place in the stack.

Use it for voice and call states, "live" indicators, or a hero with one centred message. For rings that turn instead of breathe, use Circles; for ripples from changing spots across the surface, Drops; for a beam sweeping over range rings, Sonar.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { Ripple } from "@/components/ui/ripple";

The rings sit behind whatever you put inside, centred in the container. Give the container a height; for the whole page, className="fixed inset-0 -z-10" with no children.

<Ripple className="flex min-h-[420px] items-center justify-center">
  <h1 className="text-4xl font-semibold">Always listening</h1>
</Ripple>

Demos

Avatar

size={96} starts the rings small enough to sit just outside a round avatar, for a "calling…" state in a profile card; the rest spread out to the card's corners.

Preview width

Color

color="var(--primary)" tints the rings with your theme's primary colour, count={12} adds rings and intensity="strong" makes the innermost one stronger.

Preview width

Accessibility

The rings are decorative: they're hidden from screen readers and never take the pointer, and your content stays on top in normal flow. With reduced motion the rings rest at full size, a still set of concentric discs. Nothing flashes. The middle, where the discs overlap, is at most about 15% of the ring colour at the default intensity, so text in your foreground colour keeps its contrast; check it if you pass intensity="strong" with a dark colour.

FAQ

How do I make it bigger or smaller?

size is the innermost ring's diameter in pixels (210). The outermost ring always passes the container's corners, and the rest spread out evenly between, so the rings fill a small card and a full page alike.

How many rings can I have?

count sets them, from 2 to 16 (8 by default). Opacity falls from the innermost ring to a sixth of it at the last, so any count fades out cleanly.

How does the stagger work?

Each ring starts its breath 3% of a cycle after the one inside it, so the pulse travels outward, and the outer rings breathe a little less deeply, so the large ones move as gently as the small. speed changes the cycle (2 seconds at 1) and the stagger with it.

Can I change the colour?

color takes any CSS colour or theme variable for the rim, the fill and the glow. By default it's your theme's --foreground, so it reads as grey on light pages and white on dark ones.

How do I stop the rings fading at the edges?

Pass fade="none". The default, radial, masks the rings toward the container's edges; top and bottom fade them toward one side instead.

Is it the same as Magic UI's Ripple?

Same idea. This one fills the container out past its corners, follows your theme, scales from one size prop, takes any colour format, doesn't add a <style> element per instance and stops for reduced motion.

API Reference

Ripple

<div> data-slot="ripple"

PropType
color?string

The rings' colour, any CSS colour: their rims, faint fill and glow. By default your theme's foreground colour.

count?number

How many rings, from 2 to 16, spread evenly from the innermost out past the corners; they fade toward the last.

Default
8
fade?"none" | "radial" | "top" | "bottom"

Where the rings fade out: toward the edges, the top, the bottom, or nowhere.

Type
"none" | "radial" | "top" | "bottom"
Default
"radial"
intensity?"subtle" | "medium" | "strong"

How strongly the innermost ring shows. @default "medium".

Type
"subtle" | "medium" | "strong"
size?number

The innermost ring's diameter, in pixels; the outermost always passes the corners, so the rest spread out between.

Default
210
speed?number

How fast the rings breathe: 1 is a breath every 2 seconds, 2 twice as fast.

Default
1
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--ripple-colorstring

The rings' colour (--foreground).

--ripple-opacitystring

The innermost ring's opacity (0.42).

--ripple-sizestring

The innermost ring's diameter (210px).

--ripple-speedstring

How fast the rings breathe, a multiplier (1).

All 100 backgrounds