@preferred-markdown-stream/vue
v0.6.0
Published
Vue bindings and runtime helpers for streaming Markdown rendering.
Readme
@preferred-markdown-stream/vue
Vue bindings and runtime helpers for streaming Markdown rendering.
- Frozen-prefix incremental rendering: per-chunk cost stays flat as the document grows.
- Incomplete Markdown protection: tables, math, links, and inline markup never flash as raw text mid-stream.
- Per-character fade-in that never re-animates already-rendered text.
- Lazy Shiki (per-language grammar loading) and lazy KaTeX.
Installation
pnpm add @preferred-markdown-stream/vue vueUsage
import {
createStreamingMarkdownVNodes,
createVNodeRendererComponent,
splitContent,
} from '@preferred-markdown-stream/vue'
import '@preferred-markdown-stream/vue/styles.css'createStreamingMarkdownVNodes() returns formattedContent, contentFinal, contentVNodes, and debouncedLoading.
Customizing the fade animation
The built-in animation is driven by CSS variables — override them on any ancestor:
.chat-message {
--preferred-markdown-stream-animation-duration: 0.4s;
--preferred-markdown-stream-animation-timing-function: ease-out;
/* --preferred-markdown-stream-animation-name: your-own-keyframes; */
}To integrate with an existing design system, replace the class entirely and bring your own animation CSS:
createStreamingMarkdownVNodes(content, loading, {
fadeInClassName: 'message-appear',
})The default code block UI is themeable the same way via
--preferred-markdown-stream-code-* variables (bg, radius, font,
toolbar-bg, toolbar-color, copy-hover-color).
Public API
addFadeInToVNodes(children, loading, options?)configureMermaid(loader, config?)— opt into diagram rendering, e.g.configureMermaid(() => import('mermaid')); mermaid fences show their source while streaming and swap to SVG once validcreateSmoothedContent(source, options?)— typewriter smoothing: drains bursty chunks into a steady per-character reveal with proportional catch-upcreateStreamingMarkdownVNodes(content, loading, options?)— options:splitMode,fadeInClassNamecreateVNodeRendererComponent(vnodes)setCodeBlockComponent(component)— defaults toDefaultCodeBlock(language label + copy button)setCustomComponents({ a: MyLink, img: MyImage, ... })— replace rendered tags with your components; attributes arrive as props, content through the default slotsplitContent(message)/stripIncompleteMarkdown(message)
Notes
- The package currently preserves the app's existing runtime behavior.
- The heavy lifting lives in
@preferred-markdown-stream/renderer, shared with the React package; this package contributes the Vue adapter, components, and composables. fadeIn.tsadapts the framework-agnostic tree animation helper for Vue VNodes.runtime.tsstays internal and owns the Markdown renderer instance plus lazy capability loading.useStreamingMarkdown.tscontains the repeated Vue wiring that was previously duplicated inside app components.- Default animation styles are published via
@preferred-markdown-stream/vue/styles.css. - KaTeX and Shiki are loaded on demand when matching content is detected.
- The fade-in state is intentionally delayed for about 1 second after loading completes so the last rendered batch can still animate.
- Raw HTML rendering uses browser DOM APIs internally, so client-side rendering is the safest path when your Markdown may contain raw HTML.
