shadcn.io is not affiliated with official shadcn/ui
Pendulum Text hangs each letter from a thread. Brush a letter with the pointer and it swings away from it; press and every letter swings away from the press, the nearest hardest. Each one sways back and forth, smaller every time, until it hangs still again, and since no two threads are quite the same length, letters swung together slowly drift out of step. At rest each letter hangs at a slight tilt of its own.
Use it for a playful headline, a shop sign, a toy or a 404 page. For letters that wobble on their own, use Wobble Text; for a slow drift that never stops, Drift Text. A swing is a CSS keyframe animation the install adds to your stylesheet, a damped turn about a point above the letter; a handler writes how hard and which way to a CSS variable and restarts it, with no state, no animation library and no frame loop. With reduced motion the letters hang still.
Installation
Usage
import { PendulumText } from "@/components/ui/pendulum-text";<h1>
<PendulumText text="Swing" />
</h1>Demos
Angle
angle is the widest a letter swings either way, 20° by default, and duration how long a swing takes to die down, 2400 ms. A gentle sway wants a small angle and a short swing; a wild one, both larger.
Strings
The threads are faint lines in the text's own colour. strings={false} hides them; the letters still hang from the same point above them.
Accessibility
Screen readers read the text once, from a visually hidden copy, never letter by letter. The swing 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. The letters stay readable as they sway, and with reduced motion they hang still, each at its slight tilt.
FAQ
Is it a physics simulation?
No. Every swing is the same damped keyframe animation: a quick kick out, then sways through the rest position, each about two thirds of the last and just as long, the way a real pendulum keeps its beat as it dies down. What differs from letter to letter is how hard it's pushed, which way, and its beat, a tenth longer or shorter than the next one's, all CSS variables.
Why doesn't a swinging letter answer the pointer?
A letter that's already swinging ignores a brush until it's still, so a pointer resting at its edge can't keep it going forever. A press swings every letter again, from wherever it is.
Why do neighbouring letters overlap mid-swing?
At wide angles neighbours swing into each other's space for a moment, like charms on a bracelet. Keep angle under about 25° for tightly set text, or give it some letter spacing.
Can I style the threads?
Each thread is its letter's ::before, a 1px line in the text's colour at a quarter strength, so it swings with the letter. Style [data-slot=pendulum-text-char]::before to change it, or pass strings={false} to hide it.
API Reference
PendulumText
<span> data-slot="pendulum-text"
textstring
The text.
angle?number
The widest a letter swings either way, in degrees. @default 20.
duration?number
How long a swing takes to die down, in milliseconds. @default 2400.
strings?boolean
A faint thread above each letter, the string it hangs from. @default true.
- Default
true
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.
--pendulum-text-anglestring
The widest a letter swings either way (20deg).
--pendulum-text-durationstring
How long a swing takes to die down (2400ms).
Related
- Pro
Wobble Text
MotionLetters that rock on their own
- Pro
Elastic Text
InteractiveLetters stretch, then spring back
- Pro
Gravity Text
MotionLetters that fall and bounce
- Pro
Ripple Text
InteractiveA wave from where you click
- Pro
Shatter Text
InteractiveLetters that burst apart on a click
- Pro
Turn it over
Tilt Text
InteractiveThe word tilts in 3D to the pointer