Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Ripple Text for React

Text that ripples like a pond where it's pressed, a wave running out from the letter under the pointer. For React with Base UI, when a headline should answer a tap.

Framework

Ripple Text turns a line into the surface of a pond. Press a letter and a wave runs out from it to both ends of the text: each letter bobs up and settles a beat after its neighbour, a little lower the further the wave has come. Press again, anywhere, and a fresh wave starts from there.

Use it for a playful headline, a 404 page or a title that should answer a tap. For a wave that rolls on its own, use Wave Text; for a ripple on a button, Ripple Button. A press writes the letter's place to a CSS variable and restarts a CSS keyframe animation the install adds to your stylesheet, delayed on each letter by its distance from that place: no state, no animation library and no frame loop. With reduced motion the letters stay put.

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 { RippleText } from "@/components/ui/ripple-text";
<h1>
  <RippleText text="Make a splash" />
</h1>

Demos

Intensity

intensity is how high the first crest lifts the letter pressed: subtle, medium (the default) or strong. Further out the wave is lower, never under a quarter of that.

Preview width

Timing

stagger is the time the wave takes from one letter to the next, 45 ms by default, so a lower value runs it faster; duration is how long one letter takes to bob and settle, 900 ms.

Preview width

Accessibility

Screen readers read the text once, from a visually hidden copy, never letter by letter. The ripple is decoration: it answers the pointer only, has no stop in the tab order and changes nothing, so keyboard and screen reader users miss nothing, and the letters are back on their line within a second. With reduced motion a press does nothing.

FAQ

How does the wave travel?

Each letter knows its place in the text. A press writes the pressed letter's place to a CSS variable, and each letter's bob starts after its distance from that place times stagger. Flipping a data-wave attribute between two names restarts the bob on every letter at once, so a second press starts a fresh wave from wherever it lands.

Does it ripple across lines?

The wave runs along the text in reading order, so on wrapped text it carries from the end of one line to the start of the next, more like a wave along a rope than rings on water.

What happens if I press between two words?

The wave starts from the middle of the text.

Does it work on touch screens?

Yes: a tap starts a wave from the letter under the finger.

Does it run on every frame?

No. A press writes one variable and one attribute; the browser runs the animation in CSS. Nothing runs while the text is still.

What happens with reduced motion?

The letters stay on their line: a press does nothing.

API Reference

RippleText

<span> data-slot="ripple-text"

PropType
textstring

The text.

duration?number

How long one letter takes to bob and settle, in milliseconds. @default 900.

intensity?"subtle" | "medium" | "strong"

How high the wave lifts the letters. @default "medium".

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

The time the wave takes from one letter to the next, in milliseconds: lower runs it faster.

Default
45
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

Forwarded to the part.

AttributeType
data-index?string

Mirrors index.

CSS variableType
--ripple-text-durationstring

One letter's bob (900ms).

--ripple-text-heightstring

How high the first crest lifts a letter (0.3em).

--ripple-text-staggerstring

The time the wave takes from one letter to the next (45ms).

All 97 text effects