shadcn.io is not affiliated with official shadcn/ui
Gravity Text lets go of its letters. Click it, or let it scroll into view, and the letters drop one by one, tumble as they fall, bounce twice and come to rest in a heap at the bottom of its box, each at its own angle; click again and they fly back up into place. A paragraph can fall a word at a time, piling up line on line.
Use it for an easter egg, a 404 page, a playful call to action, or a block of words that collapses as it scrolls into view. For letters that bounce in place, use Bouncing Text; for text that breaks apart instead, Shatter Text. It's a staged fall, not a physics simulation: when it drops, each letter's distance to the floor is measured once and written to a CSS variable, and a CSS transition the install adds to your stylesheet carries it there on a curve that speeds up like a falling stone, then bounces; when each letter lets go and how it lands come from its place in the text. No physics engine and no frame loop. With reduced motion the letters are simply down, or up.
Installation
Usage
import { GravityText } from "@/components/ui/gravity-text";Give it a height: the bottom of its box is the floor.
<h1>
<GravityText className="h-64" text="Drop it" />
</h1>Demos
Words
by="words" drops each word whole, for a paragraph that collapses into a box, or for scripts whose letters join, such as Arabic. With trigger="view" it falls once it's half in view; a click then lifts it and drops it again. The lines land on each other, the lowest first.
Controlled
fallen holds the state yourself: here a button beside the text drops it and lifts it. trigger="manual" leaves the text itself unclickable, for text inside your own button or link, and onFallenChange reports each change a click or the view makes.
Accessibility
Screen readers always hear the text whole: the falling letters are hidden from them, and the text is read once, as the name of a real button laid over the whole box, with aria-pressed saying whether it has fallen. Tab reaches it, and Enter or Space drops it or lifts it, like a click. With trigger="manual" there's no button, just the text, read once. With reduced motion the letters are down or up at once, without falling.
- Tab
- Move focus to the text.
- Enter
- Drop the letters, or lift them back up.
- Space
- Drop the letters, or lift them back up.
FAQ
Is it a physics simulation?
No, it's staged. Each letter's fall is worked out once, when it drops: how far it is to the floor, how far it drifts and turns, and when it lets go, from its place in the text. A CSS transition then plays the fall on a curve shaped like gravity, with two bounces. Letters don't collide: the lines of a paragraph land on each other because each one rests where the lines below it will be.
Where do the letters land?
At the bottom of the component's own box. Give it a height, such as className="h-64", or let a flex or grid parent stretch it. If it's no taller than its text, the letters only tumble where they are.
Does the page move when the letters fall?
No. The letters only move visually, so the text keeps its place in the layout and nothing below it shifts, fallen or not.
What if the box changes size while the letters are down?
They're measured as they fall, so they stay where the floor was. Lift them and drop them again to land on the new floor.
Can it fall on its own?
Yes: trigger="view" drops it once it's half in view, and defaultFallen drops it as soon as it's on the page. To drop it from anything else, such as a timer or a form error, hold fallen yourself.
API Reference
GravityText
<span> data-slot="gravity-text"
fallen?boolean
Whether the letters lie fallen, to hold that state yourself.
defaultFallen?boolean
Whether it starts fallen, when it keeps its own state. @default false.
- Default
false
onFallenChange?(fallen: boolean) → void
Called with the new state each time it falls or stands back up.
- Parameters
fallen– boolean- Returns
void
textstring
The text.
by?"characters" | "words"
What falls on its own: each character, or each word (for scripts whose letters join, such as Arabic, or for a paragraph that falls in pieces).
- Type
"characters" | "words"- Default
"characters"
duration?number
How long a letter takes to fall about 240 pixels and bounce to rest, in milliseconds; a longer fall takes a little longer, as under gravity.
- Default
1000
trigger?"click" | "view" | "manual"
What drops it: a click on it (a real button, which lifts it back up
too), scrolling into view (a click then lifts and drops it again), or
only fallen, for text inside your own button or link.
- Type
"click" | "view" | "manual"- Default
"click"
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
Merged with the part's classes.
data-state?string
"fallen" when shown is true, otherwise "standing".
--gravity-text-durationstring
A fall of about 240 pixels, bounces included (1000ms).
Related
- Pro
Bouncing Text
MotionLetters that hop and come back
- Pro
Shatter Text
InteractiveLetters that burst into shards
- Pro
Pendulum Text
InteractiveLetters that swing on strings
- Pro
Ripple Text
InteractiveA wave from where you click
- Pro
Inertia Text
InteractiveThrow the word, it springs home
- Pro
Stretch Text
MotionLetters that squash against the line