Streaming Markdown
StreamingMarkdown renders an AI's Markdown answer as tokens arrive, without flashes of raw syntax, HTML injection or a full re-render on every word.
Import
Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.
// npm install yugen-uiimport { StreamingMarkdown, parseMarkdown } from "yugen-ui";Variants
Each tile is a standalone example: hover to copy, or press Code to see the source.
To do
- Done: Add color tokens
- Done: Check contrast
- Not done: Write the docs
Unsafe links like click here render as plain text.
Task list & unsafe links
A - [x] item gets an icon plus the hidden text “Done:”. A javascript: link is removed and only its label remains.
Note: the colorBrandBackground token follows data-brand.
- Light: Brand80
- Dark: Brand70
Small size
size="small" uses caption1, for notes, reasoning blocks and cards in a panel.
Usage
- Pass the whole growing string and keep streaming on until the last token arrives. The component handles unfinished syntax.
- Set headingOffset to match the heading level of the surrounding page (default 2: # → h3).
- Inside a streaming MessageBubble, set caret={false} so there aren't two carets.
- Don't build HTML strings yourself or use dangerouslySetInnerHTML for model answers.
- Don't turn on announceWhenDone inside a MessageScroller. The answer would be read twice.
- Don't expect full CommonMark: raw HTML, images, reference links and indented code aren't supported.
Props
| Prop · Type | Default | Description |
|---|---|---|
| childrenstring | Default: — | Markdown content. |
| streamingboolean | Default: false | Tolerates unfinished syntax, shows the caret, sets aria-busy. |
| headingOffsetnumber | Default: 2 | Added to the heading level; never produces an h1. |
| citationsCitationSource[] | Default: — | Sources for [1] / [^1], rendered as Citation chips. The chip's preview card loads on demand, right after the first chip appears. |
| breaksboolean | Default: true | Turns single line breaks into <br>. |
| caretboolean | Default: true | Caret while streaming. |
| size"small" | "medium" | Default: "medium" | caption1 or body1. |
| announceWhenDoneboolean | Default: false | Reads the plain text through a live region when the stream ends. |
| parseMarkdown | Default: — | The parser on its own; sanitizeHref and markdownToPlainText are exported too. |
Messages
Text built into the component: labels, aria-labels, screen reader announcements.
English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.
messages.streamingMarkdown
| Key · Type | Default (English) | messagesVi |
|---|---|---|
| newTabstring Chữ ẩn sau link mở tab mới. | Default (English)"(opens in new tab)" | messagesVi"(mở tab mới)" |
| taskDonestring Chữ ẩn trước mục danh sách việc đã xong / chưa xong. | Default (English)"Done:" | messagesVi"Đã xong:" |
| taskTodostring | Default (English)"Not done:" | messagesVi"Chưa xong:" |
| tablestring Tên vùng cuộn của bảng. | Default (English)"Table" | messagesVi"Bảng" |