Design & UI
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.
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.
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>
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} />,
};
isStreaming && !text so an empty assistant bubble does not sit blank before the first token.key) throws away its incremental work and reintroduces flicker. Keep a stable key and change only the children.javascript: URLs. Constrain or sanitize the a handler.Related
Added 2026-07-01. Back to the Skill Library.

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.