Glin UI
Signature / Molecule

Typewriter

Character-by-character typing animation with blinking cursor and loop support.

Installation$

Install from
pnpm dlx @glinui/cli@latest add typewriter

Prefer 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-label set to the full text value 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$

PropTypeRequiredDefaultDescription
cursorbooleanNotrueShow a blinking cursor. Default: true
cursorCharstringNo"|"The cursor character. Default: "|"
delaynumberNo0Initial delay before typing starts, in ms. Default: 0
deleteSpeednumberNo30Milliseconds per character when deleting. Default: 30
engineEngineNameNo-Engine override: `css` (default), `motion`, `gsap` or a registered custom engine.
loopbooleanNofalseLoop the typing animation. Default: false
motionMotionLevelNo-Motion override. `none` renders the static final state, `subtle` is opacity only.
onComplete() => voidNo-Callback fired when a word finishes typing (fires per cycle).
pauseDurationnumberNo1500Pause at end before deleting/retyping, in ms. Default: 1500
speednumberNo50Milliseconds per character when typing. Default: 50
textstringNo-The text to type out (single string mode).
wordsstring[]No-Array of words/phrases to cycle through (multi-word mode).

Source$

import { Typewriter } from "@glinui/ui"
packages/ui/src/components/typewriter.tsx

Generated API Snapshot

Beta

Auto-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

PropTypeRequiredDefaultDescription
cursorbooleanNotrueShow a blinking cursor. Default: true
cursorCharstringNo"|"The cursor character. Default: "|"
delaynumberNo0Initial delay before typing starts, in ms. Default: 0
deleteSpeednumberNo30Milliseconds per character when deleting. Default: 30
engineEngineNameNo-Engine override: `css` (default), `motion`, `gsap` or a registered custom engine.
loopbooleanNofalseLoop the typing animation. Default: false
motionMotionLevelNo-Motion override. `none` renders the static final state, `subtle` is opacity only.
onComplete() => voidNo-Callback fired when a word finishes typing (fires per cycle).
pauseDurationnumberNo1500Pause at end before deleting/retyping, in ms. Default: 1500
speednumberNo50Milliseconds per character when typing. Default: 50
textstringNo-The text to type out (single string mode).
wordsstring[]No-Array of words/phrases to cycle through (multi-word mode).