--- description: Choose between content and nodes, understand the render pipeline, and wire markstream-vue into Vite, VitePress, Nuxt, and streaming UIs. --- # Usage & API This page shows how to wire `markstream-vue` into common stacks, how the parser fits into the renderer, and which docs to visit when something looks odd (reset order, Tailwind/UnoCSS layers, VitePress integration). ## Choose `content` or `nodes` first | Situation | Recommended input | |-----------|-------------------| | Docs pages, static articles, low-frequency updates | `content` | | SSE, token streaming, AI chat, or frequent incremental updates | `nodes` + `final` | | SSR or worker-preparsed content | `nodes` | If you only need built-in configuration, stay in this page and [Props & Options](/guide/props). If you need to replace rendering behavior, jump to [Override Built-in Components](/guide/component-overrides). If your real goal is an AI chat surface, token stream, or SSE response viewer, use the dedicated [AI Chat & Streaming](/guide/ai-chat-streaming) path instead of piecing the docs together manually. If your real goal is a docs site or VitePress theme, use [Docs Site & VitePress](/guide/vitepress-docs-integration) for the end-to-end `content` + `enhanceApp` + CSS setup. ## Minimal render ```vue twoslash ``` ```css @import 'modern-css-reset'; @layer components { @import 'markstream-vue/index.css'; } ``` ## VitePress + custom tags If this is your main use case rather than a one-off example, continue with the dedicated [Docs Site & VitePress](/guide/vitepress-docs-integration) path after this section. In VitePress, register your custom node component once in `enhanceApp`, then use `custom-html-tags` on `MarkdownRender` to let the parser emit custom nodes automatically. ```ts twoslash import type { Component } from 'vue' import MarkdownRender, { setCustomComponents } from 'markstream-vue' // docs/.vitepress/theme/index.ts import DefaultTheme from 'vitepress/theme' import 'markstream-vue/index.css' declare const ThinkingNode: Component export default { extends: DefaultTheme, enhanceApp() { setCustomComponents('docs', { thinking: ThinkingNode }) }, } ``` ```md ``` Tip: unknown HTML-like tags (such as ``) render as raw HTML elements once closed. Incomplete or malformed fragments stay as plain text so they do not swallow nearby Markdown. Add the tag name to `custom-html-tags` when you want custom node output (type + attrs/content). ## Parser pipeline ```ts twoslash import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue' const md = getMarkdown() const nodes = parseMarkdownToStructure('# Title', md) // pass nodes to ``` - `getMarkdown(msgId?, options?)` returns a configured `markdown-it-ts` instance. - `parseMarkdownToStructure(content, md)` transforms a Markdown string into the AST consumed by the renderer. - Combine with `setCustomComponents(id?, mapping)` to swap node renderers for a given `custom-id`. ## Streaming recommendation For low-frequency updates, passing `content` directly is convenient. For chat-style token streams or long documents, prefer parsing outside the component and passing `nodes` so Vue only reconciles the AST you hand it: ```ts twoslash import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue' const md = getMarkdown('chat') declare const source: string declare const isFinalChunk: boolean const nodes = parseMarkdownToStructure(source, md, { final: isFinalChunk }) ``` ```vue twoslash ``` That avoids reparsing the full Markdown string inside `MarkdownRender` on every tiny content update, which is usually the biggest win for SSE / AI output. For a full end-to-end rollout order, peer selection, and chat-specific tuning, continue with [AI Chat & Streaming](/guide/ai-chat-streaming). ## Component matrix For a full list of components and props, visit [Components & node renderers](/guide/components). Highlights: - `CodeBlockNode` — Monaco-powered blocks (requires `stream-monaco`). - `MarkdownCodeBlockNode` — Shiki-based lightweight highlighting. - `MermaidBlockNode` — requires `mermaid` ≥ 11 (no extra CSS). - `D2BlockNode` — requires `@terrastruct/d2` (no extra CSS). - `ImageNode` — emits `click`, `load`, `error` for custom previews. ## Styling reminders 1. **Reset first** (`modern-css-reset`, `@tailwind base`, `@unocss/reset`), then import `markstream-vue` styles. 2. **Use CSS layers** when Tailwind/UnoCSS is active (`@layer components { @import 'markstream-vue/index.css' }`). 3. **UNO/Tailwind conflicts** — follow the [Tailwind guide](/guide/tailwind) (includes UnoCSS examples) to prevent utilities from overriding renderer styles. 4. **Peer CSS** — KaTeX needs its own CSS; Mermaid/D2 do not. Monaco does not require extra CSS. ## CSS scoping (important) The package CSS is scoped under an internal `.markstream-vue` container to minimize global style conflicts (Tailwind utilities and theme variables included). - When you use `MarkdownRender`, you get this container automatically. - If you render exported node components on their own (e.g. `PreCodeNode`, `FootnoteNode`), wrap them with a container element: ```vue twoslash ``` If visuals still look wrong, reproduce the issue inside the playground (`pnpm play`) and cross-check with the troubleshooting guide before filing a bug.