Stream text

Free · MITReact Native · Expo

Text that arrives word by word: new words fade up and a caret pulses at the end, and when streaming stops it becomes one plain text block.

View as Markdown
Try it on your phone
Scan to open this demo in your phone's browser and use it with your fingers.

Installation

$ npx shadcn@latest add https://goodui.dev/native/r/stream-text.json

Then run npx expo install --fix so react-native-reanimated match your Expo SDK. Files land in components/goodui-native/stream-text.

Usage

import { useState } from "react";
import { StreamText } from "@/components/goodui-native/stream-text/stream-text";

const [text, setText] = useState("");
const [streaming, setStreaming] = useState(true);

await provider.stream({ prompt }, { onToken: (chunk) => setText((t) => t + chunk) });
setStreaming(false);

<StreamText text={text} streaming={streaming} />

When to use

Use it for
  • A model reply that streams in.
  • Short generated text that should feel live.
Reach for something else
  • Text that already exists: use Text.
  • Markdown or code: it renders plain text only.

API reference

PropTypeDefault
text*
The text so far. Append to it as tokens arrive.
string—
streaming
Still arriving: new words fade up and a caret pulses at the end.
booleanfalse
textStyleStyleProp<TextStyle>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

Motion and haptics

  • Each new word fades up 5 pt over 240 ms, and the caret pulses.
  • Reduced motion: words appear at once and the caret holds still.
  • One animated view per word, only in the paragraph still arriving. Finished paragraphs are plain text, and the whole reply becomes one block at the end.

Accessibility

  • Each finished sentence is announced once: through a hidden live region, or an announcement on iOS. The text so far stays readable on focus. Finished text is plain Text.

Notes for AI

  • Pass the whole text so far, not the newest chunk.
  • Set streaming to false when the reply ends, and keep it mounted so the last sentence is announced.
  • Chinese, Japanese and Thai split with Intl.Segmenter. Where the engine lacks it, they fall back to characters and Thai clusters, which can wrap inside a word until the reply ends.
  • Style with textStyle. It takes a Text style, not size or tone props.