Typewriter
Phrases typed out and deleted in a loop, with a caret and no layout shift.
Loading preview
Installation
npx shadcn@latest add @loomui/typewriterUsage
import { Typewriter } from "@/components/ui/typewriter"<p className="text-2xl">
Built for <Typewriter words={["landing pages", "dashboards", "docs sites"]} />
</p>The longest phrase is rendered invisibly underneath the visible one to reserve its width. Nothing around the typewriter reflows while it types, which is the usual reason this effect looks cheap.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
words | string[] | none | Phrases typed in order. |
typingSpeed | number | 70 | Milliseconds per character while typing. |
deletingSpeed | number | 40 | Milliseconds per character while deleting. |
holdDelay | number | 1600 | Milliseconds held on a finished phrase. |
loop | boolean | true | Start over after the last phrase. |
caret | boolean | true | Show the blinking caret. |
disabled | boolean | false | Render the first phrase in full, no typing. |
className | string | none | Merged onto the outer span. |
Any other <span> prop is forwarded.
Accessibility
Every phrase is rendered once in a visually hidden span, and the typed copy is
aria-hidden. A screen reader gets the full list as static text instead of a
live region firing on every keystroke. Under prefers-reduced-motion the
first phrase renders in full and nothing types.