ComponentsReveal
Character reveal
Letters arrive one at a time.
Installation
$ npx shadcn@latest add @textlab/char-revealNeeds @textlab in your components.json. Setup takes a minute.
Usage
usage.tsx
import { CharReveal } from "@/components/textlab/char-reveal/char-reveal";
<CharReveal variant="drop" text="Hello there" />Variants
fadedropspinscaleProps
| Prop | Type | Default | Description |
|---|---|---|---|
| text* | string | – | The copy. |
| variant | "fade" | "drop" | "spin" | "scale" | "fade" | fade is quiet, drop falls into place, spin turns up from the baseline, scale pops up from small. |
| as | ElementType | "span" | Rendered element. |
| trigger | "mount" | "inView" | "hover" | "manual" | "inView" | What starts the animation. manual follows `active`. |
| active | boolean | false | Drives trigger="manual". |
| once | boolean | true | In view: play once instead of on every entry. |
| delay | number | 0 | Seconds before the first part moves. |
| stagger | number | 0.02 | Seconds between parts. |
| duration | number | 0.6 (fade), 0.7 | Seconds each part takes. |
| ease | EaseName | [number, number, number, number] | "enter" | Easing token or cubic bezier. |
| reducedMotion | "user" | "always" | "never" | "user" | user follows the OS setting; always shows the still version. |
| className | string | – | Merged onto the root. |
| onComplete | () => void | – | Called when a one-shot animation finishes. |
When to use it
Reach for it
- Short display words and names.
- Moments where the arrival itself is the point.
Skip it
- Anything over ~60 letters; the tail gets long.
- Text people need to read quickly.
Accessibility and motion
Accessibility
- Letters are aria-hidden; the word is read once.
- Grapheme-aware, so emoji and accents never split.
Motion
- 20 ms between letters; the total stays under a second for most words.
- Words are nowrap, so lines never jump while letters move.
Reduced motion. Shows the text immediately.
Performance
- One motion span per letter. Fine for headings, not paragraphs.