Smoothstream does not subscribe to your model. Your application owns the transport. On each update, pass the full Markdown received so far and whether more of that same answer may still arrive.
That contract is the same in React, Vue, and the DOM adapter. Only the API shape changes: children, a markdown prop, or update().
Pass accumulated Markdown
Transport packets are an implementation detail. These two deliveries should present the same way:
Keep a string that grows as tokens arrive, and pass that string into Smoothstream. If several updates land in one frame, the adapters coalesce them and plan from the latest snapshot.
Signal that input is still open
receiving is the end-of-input flag, not a playback mode.
receiving | Meaning |
|---|---|
true | This snapshot may still grow or change shape. Unsafe Markdown stays withheld. |
false | This answer is complete. Remaining safe content can flush and finish presenting. |
The default is false. For a live generation, set receiving to true as soon as you mount the stream, then flip it to false when the model finishes. Leave the instance mounted so the scheduled reveal can complete.
Choose streaming or static
mode controls how content enters the page. It is independent of reduced-motion policy.
mode | Use it for |
|---|---|
"streaming" (default) | The answer that is still arriving, or that has just finished and is still presenting. |
"static" | History, cached messages, and other Markdown that should appear immediately. |
Do not switch a live instance from "streaming" to "static" when receiving becomes false. Close input and let presentation finish. Mount a new instance with mode="static" when the Markdown was already complete at mount time.
What readers see while input is open
Smoothstream is not a generic typewriter over whatever the parser currently believes. While receiving is true:
- Inline emphasis, strikethrough, links, and inline code wait until their delimiters are confirmed.
- Links stay non-interactive until the label has finished entering.
- Fenced code commits complete lines; an unfinished last line flushes when input closes.
- Tables hold extra rows so column widths can settle before a row is revealed.
- Lists reveal completed items without waiting for the entire list to close.
- Images start loading as soon as the URL is known, without blocking later blocks.
The destination is ordinary semantic HTML. Temporary reveal spans compact away when a block has settled.
Accessibility
The Markdown root is a normal document subtree, not a live region. Do not put aria-live, role="status", role="log", or role="alert" on that root or an ancestor. Character admission and compaction would then announce continuously.
Each streaming instance owns a separate, visually hidden role="status" region. After receiving is false, presentation has finished, and pending resources have settled, it announces Content ready. once. Screen-reader users then navigate the semantic headings, lists, links, and tables as usual.
mode="static" skips that announcement. Use it for history that is already on the page.

