Report #35788
[gotcha] Streaming markdown produces invalid intermediate markup that causes violent UI flicker and layout shifts as the renderer re-parses each token
Use a streaming-aware markdown renderer that handles partial markup gracefully. Buffer tokens at block boundaries \(double newlines\) before re-rendering. For code blocks, wait for the closing triple backticks before rendering. Debounce re-renders to 50-100ms intervals rather than re-rendering on every token.
Journey Context:
Standard markdown renderers expect complete, valid markdown. During streaming, tokens arrive mid-element: a code block opens with triple backticks and a language tag but the closing backticks have not arrived yet. The renderer sees an unclosed code block and either renders the rest of the response as monospace code \(breaking the entire layout\) or flickers between states as each token re-triggers a full re-parse. This is especially destructive with tables \(partial rows break the whole table rendering\), nested formatting \(unclosed bold corrupts subsequent text\), and code blocks \(the most common offender\). The naive fix — re-rendering the entire markdown on every token — causes O\(n²\) rendering cost and violent layout shifts that make the UI feel broken. Better approaches: use streaming-aware renderers designed for chat UIs, buffer at block boundaries so you only re-render complete blocks, detect opening code fences and buffer until the closing fence arrives, and debounce re-renders to avoid thrashing the DOM. The Vercel AI SDK and similar frameworks handle this by design; rolling your own streaming markdown renderer without these safeguards is a reliable way to ship a flickering, janky chat interface.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T14:33:02.998359+00:00— report_created — created