Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Stretch Text for React

Text made of rubber, each letter squashing flat against the line and springing up tall, one after another. For React with Base UI, when a playful headline needs some bounce.

Framework

Stretch Text squashes and stretches a line one letter at a time: each one squashes flat and wide against the line, springs up tall and thin, then settles, the way a cartoon animator draws an impact. A ripple of them runs through the word, then the line rests before the next round.

Use it for a playful headline, a game, a kids' app, a button label that should feel springy. For letters that leap off the line instead of changing shape, use Bouncing Text; for letters that rock in place, Wobble Text. Each letter runs a CSS keyframe animation the install adds to your stylesheet, scaled from its foot and delayed by its place in the text, with no animation library. With reduced motion the text keeps its shape.

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 { StretchText } from "@/components/ui/stretch-text";
<h1>
  <StretchText text="Boing!" />
</h1>

Demos

Intensity

intensity is how far each letter squashes: subtle gives up 15% of its height, medium, the default, a quarter, strong about a third. Each letter widens as it flattens, so it keeps about the same area.

Preview width

Stagger

stagger is the time between one letter squashing and the next, 80 ms by default: a short one sends a quick ripple through the word, a long one lets each letter land on its own. loop={false} plays one round when the page shows the text.

Preview width

Accessibility

Screen readers read the text once, as plain text, from a visually hidden copy; the stretching letters are hidden from them. Words wrap whole, and the line keeps its direction on a right-to-left page. No letter loses more than about a third of its height, and only for a moment, so the text stays readable. With reduced motion it keeps its shape.

FAQ

What is squash and stretch?

The first principle of cartoon animation: a thing flattens as it hits and stretches as it springs away, keeping its volume. Each letter here gets shorter and wider, then taller and thinner, then settles, which is what makes it read as rubber rather than a glitch.

Why do the letters seem to hit the ground?

Each letter is scaled from its foot, so its base stays on the line and only its top moves, as if it landed there.

Why do the rounds overlap in a long text?

A round is duration, 2000 ms by default, and the squash and stretch take its first two fifths. When the ripple through a long text takes longer than the rest of the round, the first letters start again before the last have settled. Lengthen duration or shorten stagger to keep the rounds apart.

How is it different from Bouncing Text?

Stretch Text keeps every letter on the line and changes its shape. Bouncing Text lifts the letters off the line and keeps their shape.

Do the wider letters push their neighbours?

No. The letters change shape with transforms, which never change the layout: a squashed letter may touch its neighbour for a moment, but the line keeps its size.

What happens with reduced motion?

The letters keep their shape and stay still, whether it loops or not.

API Reference

StretchText

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

PropType
textstring

The text. Its line breaks (\n) are kept.

duration?number

One round: a letter's squash and stretch and the rest after it, in milliseconds. The squash and stretch take the first two fifths.

Default
2000
intensity?"subtle" | "medium" | "strong"

How far each letter squashes and stretches. @default "medium".

Type
"subtle" | "medium" | "strong"
loop?boolean

Whether it keeps going; false plays one round, when the page shows it.

Default
true
stagger?number

The time between one letter squashing and the next, in milliseconds.

Default
80
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.

CSS variableType
--stretch-text-amountstring

How much a letter squashes (0.25, a quarter of its height).

--stretch-text-durationstring

One round, squash, stretch and rest (2s).

--stretch-text-staggerstring

The time between one letter squashing and the next (80ms).

All 97 text effects