Flip Text

Craft

npx shadcn add https://try.pungrumpy.com/r/flip-text.json

A split-flap style text component that animates characters one by one. Supports one-line usage or a composable API with Group, Trigger, and Text—all styled via data-state and className.

Hover or click to replay

How It Works

The component renders each character in a grid of tiles that flip from a random character toward the target. The effect is achieved with CSS animations and a small amount of React state—no motion library. Key behaviors:

  1. Replay contextFlipText.Group holds animationKey, triggerReplay, and hasInitialized. The trigger (hover or click) calls triggerReplay, which bumps animationKey inside startTransition, so each tile’s effect re-runs and the flip sequence plays again without blocking the UI.

  2. Per-tile animation — Each tile runs two animations: an entrance (flip-text-in: opacity and translateY) and a flip (flip-text-flip: rotateX from -90deg to 0). Keyframes live in the package’s style.css. Delays are derived from the tile index (0.15 * index) so tiles animate in a staggered wave. Duration and easing are fixed in the component (e.g. 0.3s ease-out for entrance, 0.25s cubic-bezier for the flip).

  3. State and styling — Tiles expose data-state="settled" or data-state="flipping". You style via Tailwind (e.g. data-[state=settled]:bg-background data-[state=flipping]:bg-tertiary/20) so no inline color or background is required. The root and the flip face both use the same data-state and transition-colors for a consistent look.

  4. Composable API — Use <FlipText text="HELLO" /> for the default (Group + Trigger + Text), or compose manually: FlipText.Group wraps FlipText.Trigger and FlipText.Text. The trigger supports asChild so you can merge the replay behavior into your own button or link.

Characters outside A–Z and 0–9 render as spaces (fixed-width gaps). The component is keyboard and screen-reader friendly: the default trigger is a button with aria-label set from the text prop.

Was this helpful?