Typewriter
Character-by-character typing animation with blinking cursor and loop support.
pnpm dlx @glinui/cli@latest add typewriterInstallation$
pnpm dlx @glinui/cli@latest add typewriterPrefer the package?
Usage$
Typewriter is a "use client" component. Place it inline to type out text character by character with an optional blinking cursor. The text prop controls what gets typed.
Examples$
Word Rotation$
Pass a words array to cycle through multiple phrases. Each word is typed, deleted, then the next one types out.
Build
"use client"import { Typewriter } from "@glinui/ui"
export function TypewriterWordsDemo() {return ( <div className="flex items-center justify-center p-8"> <h2 className="text-3xl font-bold"> Build{" "} <Typewriter words={["interfaces", "experiences", "products", "the future"]} speed={60} deleteSpeed={40} pauseDuration={2000} className="text-accent" /> </h2> </div>)}Loop$
Enable loop to continuously retype a single text after a pause.
"use client"import { Typewriter } from "@glinui/ui"
export function TypewriterLoopDemo() {return ( <div className="flex items-center justify-center p-8"> <p className="text-xl font-medium text-[var(--color-muted)]"> <Typewriter text="Building the future of UI..." loop speed={60} pauseDuration={2000} /> </p> </div>)}Custom Cursor and Speed$
Use cursorChar to change the cursor character and speed to control typing pace.
"use client"import { Typewriter } from "@glinui/ui"
export function TypewriterCustomDemo() {return ( <div className="flex items-center justify-center p-8"> <code className="text-lg font-mono text-accent"> <Typewriter text="npm install @glinui/ui" speed={30} cursorChar="_" delay={500} /> </code> </div>)}No Cursor$
Set cursor={false} to hide the cursor entirely.
"use client"import { Typewriter } from "@glinui/ui"
export function TypewriterNoCursorDemo() {return ( <div className="flex items-center justify-center p-8"> <p className="text-2xl font-semibold"> <Typewriter text="Clean, no cursor." cursor={false} speed={40} /> </p> </div>)}Engines$
Typewriter drives its main animation through the pluggable motion engine. Pass engine="css" | "motion" | "gsap", wrap a subtree in MotionEngineProvider, or set data-glin-engine on <html>. The css engine is built in and dependency free; motion and gsap are opt-in through @glinui/motion/register/*. Motion level none renders the final state and subtle is opacity only.
Engine comparison$
CSS
Motion
GSAP
// Same component, three engines. motion and gsap are opt-in:// import "@glinui/motion/register/motion"// import "@glinui/motion/register/gsap"<Typewriter engine="css" text="Deploying to production" speed={40} loop />
<Typewriter engine="motion" text="Deploying to production" speed={40} loop />
<Typewriter engine="gsap" text="Deploying to production" speed={40} loop />Accessibility$
- The component renders with
aria-labelset to the fulltextvalue so screen readers announce the complete text immediately. - The typed characters and cursor are both
aria-hidden="true"to prevent partial reading. - No interactive elements are created by the typewriter itself.
Reduced Motion$
When prefers-reduced-motion: reduce is active, the full text is displayed immediately with no animation. The cursor remains visible but does not blink.
API Reference$
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
cursor | boolean | No | true | Show a blinking cursor. Default: true |
cursorChar | string | No | "|" | The cursor character. Default: "|" |
delay | number | No | 0 | Initial delay before typing starts, in ms. Default: 0 |
deleteSpeed | number | No | 30 | Milliseconds per character when deleting. Default: 30 |
engine | EngineName | No | - | Engine override: `css` (default), `motion`, `gsap` or a registered custom engine. |
loop | boolean | No | false | Loop the typing animation. Default: false |
motion | MotionLevel | No | - | Motion override. `none` renders the static final state, `subtle` is opacity only. |
onComplete | () => void | No | - | Callback fired when a word finishes typing (fires per cycle). |
pauseDuration | number | No | 1500 | Pause at end before deleting/retyping, in ms. Default: 1500 |
speed | number | No | 50 | Milliseconds per character when typing. Default: 50 |
text | string | No | - | The text to type out (single string mode). |
words | string[] | No | - | Array of words/phrases to cycle through (multi-word mode). |
Source$
import { Typewriter } from "@glinui/ui"Generated API Snapshot
Beta
Generated API Snapshot
BetaAuto-extracted from TypeScript source in packages/ui/src/components/typewriter.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.
Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata
Primary Props Type
TypewriterProps
TypewriterProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
cursor | boolean | No | true | Show a blinking cursor. Default: true |
cursorChar | string | No | "|" | The cursor character. Default: "|" |
delay | number | No | 0 | Initial delay before typing starts, in ms. Default: 0 |
deleteSpeed | number | No | 30 | Milliseconds per character when deleting. Default: 30 |
engine | EngineName | No | - | Engine override: `css` (default), `motion`, `gsap` or a registered custom engine. |
loop | boolean | No | false | Loop the typing animation. Default: false |
motion | MotionLevel | No | - | Motion override. `none` renders the static final state, `subtle` is opacity only. |
onComplete | () => void | No | - | Callback fired when a word finishes typing (fires per cycle). |
pauseDuration | number | No | 1500 | Pause at end before deleting/retyping, in ms. Default: 1500 |
speed | number | No | 50 | Milliseconds per character when typing. Default: 50 |
text | string | No | - | The text to type out (single string mode). |
words | string[] | No | - | Array of words/phrases to cycle through (multi-word mode). |