Skip to content

Ripple

Concentric rings that swell outward from the centre, as a calm backdrop behind a heading or a call to action. Content goes in front of the rings.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

import { Ripple } from "@rdloom/react";

export default function RippleBasicExample() {
  return <Ripple className="h-64 w-[26rem] max-w-full rounded-xl border border-[var(--rd-color-border-default)]" />;
}

Installation

npx rdloom add ripple

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/ripple.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { Ripple } from "@rdloom/react";

<Ripple className="h-64 w-[26rem] max-w-full rounded-xl border border-[var(--rd-color-border-default)]" />

With content

Join the waitlist

Be first to know when it is ready.

import { Ripple } from "@rdloom/react";

export default function RippleWithContentExample() {
  return (
    <Ripple className="h-72 w-[30rem] max-w-full rounded-xl border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-subtle)]" size={150} rings={5}>
      <div className="text-center">
        <p className="text-xl font-semibold">Join the waitlist</p>
        <p className="pt-1 text-sm text-[var(--rd-color-text-muted)]">Be first to know when it is ready.</p>
      </div>
    </Ripple>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
children

Content shown in front of the rings, centred.

nodenone
size

Diameter in pixels of the innermost ring.

number210
rings

How many rings, 1 to 12.

number6
duration

Seconds for one swell.

number4
color

Colour of the rings, any CSS colour. Defaults to the strong border colour.

stringnone
isPaused

Stops the animation. Moving content that lasts more than five seconds should be stoppable.

booleanfalse
className

Classes for the wrapper: size it and give it a background.

stringnone

Accessibility

Role none, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Silent: only the content in front is read

What your code must do

  • Decoration only: the animated layers are hidden from assistive technology and never take focus
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), and the effect can also be shown still with the rdm-still class
  • The rings are low contrast by design and never carry meaning
  • Text placed over them keeps its own contrast against the page, not against the rings
  • Does not flash: nothing changes more than three times in a second (WCAG 2.3.1)
  • Optional: it is a separate component, so projects that do not add it carry none of its code

Guidelines

Use it when

  • Behind a hero heading or a sign-up block
  • An empty or waiting state that should feel calm

Avoid it when

  • Behind dense text
  • Small areas, where rings are clipped awkwardly

Don't

  • Bright, high-contrast ring colours behind text

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-border-strong
  • --rd-color-text-default