Skip to content
Pinky UI

text

Streaming Text

Token-by-token reveal with a blinking cursor, interruptible mid-stream.

  • text
  • streaming
  • chat
  • typewriter
  • cursor

Live preview

Here's a streamed response, arriving one token at a time.

Quick usage

usage
import { StreamingText } from "@pinky-ui/ai-ui";

<StreamingText text={partialResponse} streaming={isStreaming} />

Presets

Default

A natural token-arrival pace.

Default behaviour

Fast

For long responses where the reveal shouldn't outlast reading.

speed={90}

Deliberate

A slower, more legible pace for short, important messages.

speed={24}

Install

Add @pinky-ui/ai-ui as a dependency, or use the CLI to copy this component's source directly into your project — no dependency to manage, fully editable.

shell
npm install @pinky-ui/ai-ui

Prefer to run the whole repository locally instead?

repository
git clone https://github.com/florash/Pinky-UI.git
cd Pinky-UI
npm install
npm run dev

Props

PropTypeDefaultDescription
textstringThe text revealed so far — grow it as tokens arrive to stream in real time.
speednumber45Characters revealed per second while animating.
streamingbooleantrueSet to false to reveal the remaining text immediately, e.g. from a Stop button.
onDone() => voidCalled once the visible text catches up with `text`.
cursorbooleantrueShows a blinking block cursor while text is still catching up.
as"p" | "span" | "div""p"Element the text renders as.
classNamestringApplied to the outer element.

Accessibility

  • The complete text is available to screen readers immediately through a visually hidden node — nobody has to wait on the animation to hear the message.
  • The animated glyphs and blinking cursor are `aria-hidden`; only the hidden complete text is announced.

Performance

  • Reveal runs off a single requestAnimationFrame loop per instance and cancels on unmount or when `text` changes to an unrelated value.

Reduced motion

With prefers-reduced-motion: reduce, the full text renders immediately and the cursor never appears.

When to use

  • Assistant responses arriving over a stream (SSE, WebSocket, chunked fetch).
  • Any place a typewriter reveal signals "still arriving" without blocking on it.

When not to use

  • Static text that never streams — render it directly instead.
  • Long-form content where a reveal would just delay reading.