Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Anagram Text for React

Words that rearrange their own letters, each shared letter sliding to its new place. For React with Base UI, when a word should visibly turn into another made of the same letters.

Framework

Anagram Text turns one word into the next by moving its letters: every letter the two words share slides from its old place to its new one, hopping over the letters going the other way, while the letters they don't share fade out and the new ones fade in. With true anagrams (LISTEN, SILENT, TINSEL) every letter travels and nothing fades. It cycles through its words, holds the width of the longest, and pauses while the pointer is over it.

Use it for a wordplay headline, a logo that rearranges into a tagline, or any word that should seem to think. For words that change in place without moving their letters, use Morph Text; for letters that scramble through random characters before settling, Decrypted Text. A small timer counts the turns and a pure function pairs each letter with the nearest same letter in the word before; CSS keyframe animations the install adds to your stylesheet slide them, with no animation library. With reduced motion the words swap in place.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { AnagramText } from "@/components/ui/anagram-text";
<AnagramText words={["LISTEN", "SILENT", "TINSEL", "ENLIST"]} />

Demos

Phrases

A word can be a few words: a space is a letter like any other and slides to a space. Words of different lengths work too; the extra letters fade, and every word starts at the same edge, so the longest holds the width.

Preview width

Cell

Every letter has a slot of its own, so it moves by whole slots. They're one character wide, set in your monospaced font by default. For another font, set --anagram-text-cell to a width that fits its widest letter: here a light sans set wide, like display type.

Preview width

Accessibility

Screen readers read every word once, as a list (LISTEN, SILENT, TINSEL), from a visually hidden copy; the moving letters are hidden from them, so they never hear a word half rearranged. The words stop while the pointer is over them, for anyone reading slowly, and with reduced motion they swap without moving.

FAQ

How does it decide where each letter goes?

Each letter of the next word takes the nearest same letter of the word before that isn't already taken, so a letter that can stay put does, and the others travel as little as they can. A letter with no partner fades out where it stood; a letter that's new fades in at its place.

Do the words have to be anagrams?

No. Any words work: the letters they share slide and the rest fade. True anagrams look the most striking, because every letter travels and nothing fades.

Does case matter?

Yes: A and a are different letters, and won't slide into each other. Write the words in one case, as the demos do in capitals, for the most letters to travel.

Why is it monospaced?

Every letter moves by whole slots, and the slots are one character wide, which fits a monospaced font exactly. It's the default, and your className can change it; with a proportional font, set --anagram-text-cell to about the width of its widest letter (0.8em or so), or wide letters will touch.

Does it work right to left?

Yes. The slots follow the text's own direction, so a Hebrew word starts at the right and its letters slide the right way. Letters that join, as Arabic's do, show in their separate forms, since each one moves on its own.

What do screen readers hear?

Every word once, separated by commas: "LISTEN, SILENT, TINSEL, ENLIST".

What happens with reduced motion?

The words still change, each replacing the last in place, without sliding or fading.

API Reference

AnagramText

<span> data-slot="anagram-text"

PropType
wordsstring[]

The words, shown in turn from the first. The letters a word shares with the one before slide to their new places; the rest fade.

duration?number

How long each word stays, in milliseconds. @default 3000.

Default
3000
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.

AttributeType
data-turn?string
CSS variableType
--anagram-text-cellstring

The width of one letter's slot (1ch; set it for a proportional font).

--anagram-text-slotstring
--anagram-text-slotsstring
All 97 text effects