Flip Words
interlace-ui/flip-wordsFreeComponent
A headline word that flips through a list. Each replacement enters letter-by-letter out of an 8px blur while the outgoing one drifts up, blurs and scales away.
Install it
npx shadcn@latest add https://ds.interlace.tools/r/flip-words.jsonSource
1"use client";23import {4 type ComponentPropsWithoutRef,5 useCallback,6 useEffect,7 useId,8 useMemo,9 useState,10} from "react";1112// @interlace/flip-words v1.1.0 — Interlace design system.13// Docs, props and live preview: https://ds.interlace.tools/c/flip-words14// What changed since: https://ds.interlace.tools/c/flip-words#history15// Generated banner — keep it, the upgrade diff reads this version.1617/**18 * @interlace/ui — FlipWords19 *20 * A headline word that flips through a list. Each replacement enters21 * letter-by-letter out of an 8px blur while the outgoing one drifts up, blurs22 * and scales away.23 *24 * It runs itself on a `duration` dwell timer (3000ms by default), or you hand25 * it `index` + `onIndexChange` and drive it yourself.26 *27 * ## Provenance28 *29 * Our reimplementation of the Aceternity UI `FlipWords`. What is ours: a30 * numeric index with a controlled mode — upstream is uncontrolled-only and31 * derives its position from `words.indexOf(currentWord)`, which misbehaves the32 * moment the list contains a duplicate; `currentColor` instead of a hard-coded33 * `text-neutral-900 dark:text-neutral-100` pair; `pauseOnHover`; and the34 * reduced-motion branch below.35 *36 * ## Anatomy37 *38 * FlipWords (span — data-slot="flip-words")39 * ├─ span.sr-only aria-live=polite (the announced text)40 * └─ span[data-slot=flip-words-static] (under reduce)41 * | motion.span[data-slot=flip-words-word]42 * └─ span per word43 * └─ motion.span per letter44 *45 * The visible word is `aria-hidden` in BOTH branches. Everything a screen46 * reader gets comes from the polite live region, so the letter-by-letter47 * staging is never spelled out.48 *49 * ## Motion50 *51 * JS-driven — `motion/react` enter/exit variants plus a `setTimeout` cycle —52 * so the CSS reset in `styles/preflight.css` reaches none of it. It is gated53 * in JS, at both levels: `cyclingPaused` includes `reducedMotion`, so the54 * timer never fires, and the render swaps the entire `AnimatePresence` subtree55 * for a plain `<span>` carrying the active word. Under56 * `prefers-reduced-motion: reduce` you get one stable, readable word and no57 * animation object is ever constructed.58 *59 * `pauseOnHover` is documented as a no-op under reduce for the same reason:60 * there is nothing left to pause.61 *62 * ## Layout63 *64 * The outgoing word animates to `position: absolute`, so the span does not65// … truncated
More from interlace-ui
All 140 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| A11y Startera11y-starter | interlace-ui | Components | Free | no deps | |
| Accordionaccordion | interlace-ui | Components | Free | no deps | |
| Alertalert | interlace-ui | Components | Free | no deps | |
| Alert Dialogalert-dialog | interlace-ui | Components | Free | no deps | |
| Animated Gradient Textanimated-gradient-text | interlace-ui | Components | Free | no deps | |
| Animated Grid Patternanimated-grid-pattern | interlace-ui | Components | Free | no deps | |
| Animated Listanimated-list | interlace-ui | Components | Free | no deps | |
| Article Cardarticle-card | interlace-ui | Components | Free | no deps |
