Skip to content

Gravity Letters

A playful gravity field where letters, numbers, emoji, or any components you pass fall and pile up like real objects.

Click anywhere in the box

Installation

  1. 1

    Install the packages

    pnpm add clsx tailwind-merge
  2. 2

    Add the utility file

    lib/utils.ts
    import { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";
    export function cn(...inputs: ClassValue[]) {  return twMerge(clsx(inputs));}
  3. 3

    Copy and paste the code into your project

    Loading source…
  4. 4

    Update the import paths to match your project

    Point @/lib/utils to your utility file if your path aliases differ.

Usage

app/page.tsx
import GravityLetters from "@/components/ui/gravity-letters"
export function Demo() {  return (    <GravityLetters type="letters" className="h-96 w-full rounded-3xl border">      {/* anything you render inside stays clickable-through */}      <p className="absolute inset-0 grid place-items-center text-sm text-muted-foreground">        Click anywhere      </p>    </GravityLetters>  )}
// Digits instead:// <GravityLetters type="numbers" />
// Or drop your own content: emoji, icons, any component:// <GravityLetters items={["🍎", "🍊", "🍇", <Sparkles key="s" className="size-7" />]} />

Options

Pick a value to see the prop you would pass. Defaults are left out.

type
color
snippet.tsx
<GravityLetters />

Props

PropTypeDefaultDescription
type"letters" | "numbers" | "both"Default: "letters"Which pool to draw from: letters, digits, or both. Ignored when items is set.
itemsReact.ReactNode[]Default: -Your own drop pool: emoji, icons, or any components. Each drop picks a random entry. Overrides type.
gravitynumberDefault: 800Downward acceleration in px/s². Lower is floatier, higher is heavier.
sizenumberDefault: 28Base glyph size in pixels. Each drop varies slightly around it.
colorstringDefault: "currentColor"Glyph color. Defaults to currentColor so it follows your theme.
maxGlyphsnumberDefault: InfinityMax glyphs kept in the field; past the cap the oldest fade out. Unlimited by default.
deviceTiltbooleanDefault: trueTilting a phone spills the pile toward the low side. iOS asks for motion permission on the first tap.
classNamestringDefault: -Extra classes for the root element. Use it to size the field.

Click or tap anywhere to drop a glyph, or press and hold to pour a steady stream. Glyphs tumble as they fall, bounce softly when they land, and pile up into rounded hills. On phones, tilt the device to spill the pile toward the low side. Honors prefers-reduced-motion.

Credits and license

Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.

  • Free to use and modify in both personal and commercial projects.
  • Attribution to Mox UI is appreciated when using a component.
  • Please don't resell the components as your own kit.
Contact Mox UI