Design & UI
Streamdown Chat Rendering
Use when rendering streaming LLM markdown in a chat UI with Streamdown. Covers incomplete-token safety mid-stream, a custom component map for a strict design system, and code-block handling. Also use when a half-arrived token renders as broken markup, a code fence flickers while streaming, or rendered output ignores the design contract. If markdown is rendered before it is complete, use this skill.
1 file
Description
Use when rendering streaming LLM markdown in a chat UI with Streamdown. Covers incomplete-token safety mid-stream, a custom component map for a strict design system, and code-block handling. Also use when a half-arrived token renders as broken markup, a code fence flickers while streaming, or rendered output ignores the design contract. If markdown is rendered before it is complete, use this skill.
name: streamdown-chat-rendering description: Use when rendering streaming LLM output as markdown in a chat interface with Streamdown (the streaming-safe react-markdown alternative from the AI SDK ecosystem). Covers incomplete-token safety, a custom component map for a strict design system, and code-block handling.
Streamdown Chat Rendering
When to trigger
Displaying assistant messages that arrive token by token and contain markdown (headings, lists, code fences). Plain react-markdown re-parses the whole string every token and flickers or mis-renders half-open syntax mid-stream.
Why Streamdown over react-markdown here
Streamdown is built for text that is still arriving: it handles an unterminated code fence, a half-written table, or an incomplete link without collapsing the layout on every keystroke. Render the accumulated text directly:
import { Streamdown } from "streamdown";
import remarkGfm from "remark-gfm";
<Streamdown remarkPlugins={[remarkGfm]} components={MARKDOWN_COMPONENTS}>
{text}
</Streamdown>
Match the design contract with a component map
Streamdown renders default HTML elements. In a system with square corners, hairline borders, and no gradients, pass a components map so every element matches instead of shipping library defaults:
const MARKDOWN_COMPONENTS = {
a: (props) => <a className="underline underline-offset-2" {...props} />,
code: (props) => <code className="bg-neutral-100 px-1 font-mono text-[0.9em]" {...props} />,
pre: (props) => <pre className="border border-black/10 bg-neutral-50 p-3 overflow-x-auto" {...props} />,
};
Streaming UX details
- Show a blinking caret only while
isStreaming && !textso an empty assistant bubble does not sit blank before the first token. - Detect a message that is a single fenced code block and let it go full width; wrap normal prose to a readable max width.
Pitfalls
- Re-mounting the Streamdown component on every token (a changing
key) throws away its incremental work and reintroduces flicker. Keep a stable key and change only the children. - Leaving the default component styles ships rounded corners and library colors into a hard-edged system. Supply the component map.
- Rendering untrusted markdown without sanitizing links can inject
javascript:URLs. Constrain or sanitize theahandler.
Related
Added 2026-07-01. Back to the Skill Library.

Get Smarter About AI Dev
New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.