Recipes

Streaming AI chat renderer with CJK-aware Markdown and shared document references

Discovered from README cross-links · today

Content & CreativeSoftware & DevOps

Built a React/Vue streaming Markdown renderer for AI responses with math

What they did

They were building an AI assistant UI where answers stream in token by token, and the existing Markdown renderer kept flickering: incomplete code fences, footnote definitions arriving after their references, and math delimiters mangled by currency symbols. They adopted ai-markdown's React adapter, passing the full accumulated Markdown string to a single component so the engine could reuse a verified prefix on appends instead of re-parsing everything. They wrapped the chat transcript in AIMarkdownDocuments with an explicit document id so footnotes and link/image definitions were shared across the logical sections of one answer, even though several renderers were mounted. For mixed Chinese/English answers they enabled the built-in CJK-aware delimiter parsing and added pangu.js spacing so Latin words and CJK characters did not collide. They kept their own presentation layer rather than the Mantine integration, mapping headings, code blocks, and tables to their design system components, and relied on the sanitizer running before URL transformation for user-supplied links.

How it went

The transcript stopped flickering during streaming and long answers updated incrementally without full re-renders of unchanged blocks. Math and chemistry formulas rendered correctly, and CJK answers read cleanly with proper spacing. Footnotes resolved across sections of a single answer. The team kept their own UI components, so visual polish matched the rest of the product; the main remaining work was tuning custom component memoization for very large answers.

Worth knowing

The document coordination only shares definitions across renderers the application deliberately groups under one id; it does not join syntax split across arbitrary network packets, so callers must pass accumulated text, not deltas. The React-node cache and context hooks are React-specific, and Vue has API differences. pangu.js spacing is a presentation choice that can surprise users who expect exact source text, and the v2 migration removed the old object-based config channel in favor of flat props and a sealed plugin catalog.

Wiring

Install @ai-markdown/react (plus @ai-markdown/core and @ai-markdown/engine as shared deps) and pangu-js. In the chat view, hold the accumulated Markdown string in state and render one AIMarkdown component per assistant message, passing the whole string rather than streamed deltas. Wrap the message list in AIMarkdownDocuments with a document id scoped to that answer so footnote and link/image definitions resolve across sections. Enable CJK-aware delimiter parsing in the component props and apply pangu.js spacing to text nodes via a custom text component or a preprocessing step before parsing. Map heading, code, table, and list nodes to existing design-system components through the adapter's component overrides. Keep the sanitizer enabled and ordered before URL transformation, and register any custom URL schemes through typed inputs. If upgrading from 1.x, replace the object-based config channel with flat props and the five narrow hooks per the migration guide.

Try it yourself

In this repo, integrate ai-markdown's React adapter into our AI chat transcript. Pass the full accumulated Markdown string to one component per answer instead of deltas. Wrap the transcript in AIMarkdownDocuments with a stable document id so footnotes and link definitions are shared across sections. Enable CJK-aware parsing and add pangu.js spacing for mixed Chinese/English text. Keep our existing design-system components for headings, code, and tables, and confirm the sanitizer runs before URL transformation. Show me the diff and any config changes needed.

Source

Tools in this stack