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.
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 rippleCopies 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.jsonWorks, 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.
| Prop | Type | Default |
|---|---|---|
childrenContent shown in front of the rings, centred. | node | none |
sizeDiameter in pixels of the innermost ring. | number | 210 |
ringsHow many rings, 1 to 12. | number | 6 |
durationSeconds for one swell. | number | 4 |
colorColour of the rings, any CSS colour. Defaults to the strong border colour. | string | none |
isPausedStops the animation. Moving content that lasts more than five seconds should be stoppable. | boolean | false |
classNameClasses for the wrapper: size it and give it a background. | string | none |
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