markstream-vue2

Vue 2.6/2.7 streaming Markdown renderer for AI chat, LLM token streams, SSE/WebSocket output, incomplete Markdown, Mermaid, KaTeX, stream-diffs powered code blocks, and Vue 2 component rendering.
17,805 3,032
Install
npm install markstream-vue2
Latest Version:2.0.20
Vue:2
License:MIT
Last Updated:Oct 19, 2026
Links: GitHub  ·  npm
Maintainer: simon_he

markstream-vue2

Vue 2.6 / 2.7 compatibility renderer for legacy Vue 2 apps that need streaming Markdown, AI chat output, long documents, progressive Mermaid/KaTeX, and streaming code blocks.

For Vue 3 or new Vue/Nuxt projects, use markstream-vue instead.

The coordinated 2.0 family beta will use markstream-vue2@next. Before installing, verify that npm view markstream-vue2@next version reports 0.1.0-beta.1. It removes the Monaco and Shiki code-block APIs in favor of stream-diffs; read the coordinated 2.0 family migration guide before upgrading.

# Vue 2.7
pnpm add markstream-vue2@next stream-diffs

# Vue 2.6 (also register the plugin with Vue.use)
pnpm add markstream-vue2@next stream-diffs @vue/composition-api

Install

pnpm add markstream-vue2
# npm i markstream-vue2
# yarn add markstream-vue2

Requirements

  • Vue 2.6.14+ (Vue 2.7 recommended for better TS support)
  • @vue/composition-api (required for Vue 2.6.x)
  • vue and vue-template-compiler must use the same Vue 2 version

Composition API compatibility

Vue version Composition API availability What to install How to import
2.6.x Not built-in @vue/composition-api import { ref, computed, defineComponent } from '@vue/composition-api'
2.7.x Built-in None import { ref, computed, defineComponent } from 'vue'
3.x Built-in None import { ref, computed, defineComponent } from 'vue'

Notes:

  • Vue 2.6.x must install and Vue.use(@vue/composition-api).
  • Vue 2.7.x should not install @vue/composition-api.
  • Vue 3.x should use markstream-vue (not markstream-vue2).

Quick start by version

Vue 2.6.x

pnpm add markstream-vue2 vue@2.6.14 vue-template-compiler@2.6.14 @vue/composition-api
import VueCompositionAPI from '@vue/composition-api'
import MarkdownRender, { VueRendererMarkdown } from 'markstream-vue2'
import Vue from 'vue'
import 'markstream-vue2/index.css'

Vue.use(VueCompositionAPI)
Vue.use(VueRendererMarkdown)

If your app increases root font size on mobile (html / body), prefer markstream-vue2/index.px.css to avoid rem-driven scaling.

Repo example:

  • playground-vue2-cli (Vue 2.6 + Vue CLI / Webpack 4)

Start:

pnpm -C playground-vue2-cli dev

From repo root:

pnpm play:vue2-cli

Vue 2.7.x

pnpm add markstream-vue2 vue@2.7.16 vue-template-compiler@2.7.16
import MarkdownRender, { VueRendererMarkdown } from 'markstream-vue2'
import Vue from 'vue'
import 'markstream-vue2/index.css'

Vue.use(VueRendererMarkdown)

Repo example:

  • playground-vue2 (Vue 2.7 + Vite)

Start:

pnpm -C playground-vue2 dev

From repo root:

pnpm play:vue2

Vue 3.x (use markstream-vue)

pnpm add markstream-vue vue@^3

If your workspace also installs Vue 3, ensure vue-demi targets Vue 2:

pnpm vue-demi-switch 2

If you cannot run vue-demi-switch, you can force the Vue 2 build via bundler alias (common in Vue CLI / Webpack 4):

// vue.config.js / webpack config
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        'vue-demi$': 'vue-demi/lib/v2/index.cjs',
      },
    },
  },
}

Usage (Vue 2.6)

import VueCompositionAPI from '@vue/composition-api'
import MarkdownRender, { VueRendererMarkdown } from 'markstream-vue2'
import Vue from 'vue'
import 'markstream-vue2/index.css'

Vue.use(VueCompositionAPI)
Vue.use(VueRendererMarkdown)

new Vue({
  render: h => h(MarkdownRender, {
    props: {
      content: '# Hello from Vue 2',
    },
  }),
}).$mount('#app')

Streaming best practices

  • For simple chat streaming, passing content is the fastest way to integrate.
  • For high-frequency SSE / token streaming, long conversations, or very large code/table/math blocks, prefer parsing outside the renderer and pass nodes instead of reparsing the whole content string every chunk.
  • Keep viewport-priority enabled unless you explicitly want eager rendering. Mermaid / stream-diffs / D2 blocks now stay idle while offscreen and resume when they approach the viewport.
<template>
  <MarkdownRender
    :nodes="nodes"
    :final="final"
    :viewport-priority="true"
    :defer-nodes-until-visible="true"
  />
</template>

Heavy-node prop forwarding

MarkdownRender can forward framework-level props directly into specialized heavy renderers:

<template>
  <MarkdownRender
    :content="markdown"
    :mermaid-props="{
      showHeader: false,
      renderDebounceMs: 180,
      previewPollDelayMs: 500,
    }"
    :d2-props="{ progressiveIntervalMs: 500 }"
    :infographic-props="{ showHeader: false }"
  />
</template>

Notes:

  • Use kebab-case in templates: mermaid-props, d2-props, infographic-props.
  • These props are forwarded to the built-in Mermaid / D2 / Infographic blocks and to custom mermaid / d2 / infographic overrides registered with setCustomComponents(...).

Enhanced Code Blocks

stream-diffs powers enhanced code blocks across all Markstream packages (smaller runtime, no monaco-editor); a plain <pre> is rendered when it is not installed.

Install the runtime:

pnpm add stream-diffs

CodeBlockNode renders a single code block with the header, toolbar, and a stream-diffs File / FileDiff surface:

<script lang="ts">
import type { CodeBlockOptions } from 'markstream-vue2'
import { CodeBlockNode } from 'markstream-vue2'
import Vue from 'vue'

const codeBlockOptions: CodeBlockOptions = {
  overflow: 'wrap',
  diffStyle: 'unified',
  enableLineSelection: true,
}

export default Vue.extend({
  components: { CodeBlockNode },
  data() {
    return {
      node: {
        type: 'code_block',
        language: 'ts',
        code: 'const answer = 42',
        raw: 'const answer = 42',
      },
      codeBlockOptions,
    }
  },
})
</script>

<template>
  <CodeBlockNode :node="node" :code-block-options="codeBlockOptions" is-dark show-header />
</template>

Direct CodeBlockNode and top-level MarkdownRender both accept code-block-options. The shared CodeBlockOptions type covers host-managed typography/layout plus supported File/FileDiff, interaction, annotation, and callback fields; maxHeight and the single symmetric padding value use numeric CSS pixels. Use code-block-props for header/toolbar controls. Theme values are registered names and themes is the [dark, light] pair. An old Monaco JSON theme is not accepted directly: first convert it to a Shiki ThemeRegistration, then call registerCustomTheme(name, loader) from stream-diffs/pierre; see the coordinated 2.0 family migration guide. Vue 2.6 apps need @vue/composition-api; see the Webpack 4 notes above if you use Vue CLI 4.

Language-specific code block overrides

You can also register a renderer for one fenced language directly:

import { setCustomComponents } from 'markstream-vue2'

setCustomComponents('docs', {
  echarts: EChartsBlockNode,
})

Notes:

  • echarts only catches fences whose language is echarts.
  • Code block routing priority is exact language key -> built-in mermaid / d2 / infographic routes -> code_block.
  • mermaid, d2, and infographic overrides keep their specialized prop forwarding; other language keys receive the normal code-block-level bindings.

Mermaid tuning

Common mermaid-props keys for streaming scenarios:

  • renderDebounceMs: delay partial/full progressive work during rapid token bursts.
  • contentStableDelayMs: how long source mode waits before auto-switching back to preview when content stabilizes.
  • previewPollDelayMs: initial delay before preview polling tries to upgrade a partial preview into a full render.
  • previewPollMaxDelayMs: cap for preview polling backoff.
  • previewPollMaxAttempts: maximum retry count while the Mermaid source is still incomplete.

Build and size checks

pnpm --filter markstream-vue2 build
pnpm --filter markstream-vue2 build:analyze
pnpm --filter markstream-vue2 size:check

Bundle size notes

  • Optional peers are not bundled; install only the features you need.
  • Infrequent language icons are split into an async chunk and loaded on demand.
  • If you want to avoid first-hit fallback icons, preload once when the app is idle:
import { preloadExtendedLanguageIcons } from 'markstream-vue2'

if (typeof window !== 'undefined')
  void preloadExtendedLanguageIcons()

Troubleshooting

defineComponent is not a function

Cause: vue-demi is in Vue 3 mode while the app runs Vue 2.x. Fix: run pnpm vue-demi-switch 2 or alias vue-demi$ to vue-demi/lib/v2/index.cjs.

Vue packages version mismatch

Cause: vue and vue-template-compiler versions differ. Fix: align both to the same version (e.g. 2.6.14 or 2.7.16).

Cannot read properties of undefined (reading 'props')

Cause: Vue 2.6 + Composition API missing _setupProxy patch, or plugin not installed. Fix: ensure @vue/composition-api is installed + Vue.use(...), and update to the latest markstream-vue2 build.

Custom node renders trigger infinite update loop

Cause: in Vue 2.6 / Vue CLI 4, recursively mounting another MarkdownRender inside a custom node component can create a render loop when the parent renderer is still streaming. Fix: prefer NestedRenderer for nested streaming content. If you only need static HTML output, renderNestedMarkdownToHtml(...) is still available.

import { NestedRenderer } from 'markstream-vue2'

export default {
  components: { NestedRenderer },
  props: {
    node: { type: Object, required: true },
  },
}
<template>
  <NestedRenderer
    :node="node"
    custom-id="chat-demo"
    :custom-html-tags="['thinking']"
    :typewriter="false"
    :batch-rendering="false"
    :viewport-priority="false"
    :defer-nodes-until-visible="false"
  />
</template>

NestedRenderer keeps the inner content streamable, but switches the nested renderer to the nodes path so Vue 2.6 does not recurse through a second content-driven renderer.

If you cannot mount another renderer and just need a static nested body, use renderNestedMarkdownToHtml(...):

import { renderNestedMarkdownToHtml } from 'markstream-vue2'

export default {
  props: {
    node: { type: Object, required: true },
  },
  computed: {
    renderedHtml() {
      return renderNestedMarkdownToHtml(
        { node: this.node },
        {
          customHtmlTags: ['thinking'],
          customNodeClass(node) {
            return node.type === 'thinking' ? 'thinking-node__nested' : ''
          },
        },
      )
    },
  },
}

This keeps deeply nested custom content streamable without recursively mounting a second content-driven MarkdownRender / NodeRenderer.

Tailwind

If your app uses Tailwind and you want to avoid shipping duplicated utility CSS, import the Tailwind-ready output instead:

import 'markstream-vue2/index.tailwind.css'

Then include the extracted class list in tailwind.config.js:

module.exports = {
  content: [
    './src/**/*.{js,ts,vue}',
    require('markstream-vue2/tailwind'),
  ],
}

Notes

  • The Vue 2 package is a compatibility port for legacy Vue 2 apps and mirrors the Vue 3 renderer feature set where practical (virtualization, streaming code blocks, stream-diffs, Mermaid, KaTeX, tooltip singleton).
  • Optional peers are still required for those features (stream-diffs for enhanced code blocks, mermaid, katex, etc.).
  • Custom node components are supported via setCustomComponents from markstream-vue2.
  • If you only render short static Markdown, a smaller Vue 2 Markdown component may be a simpler fit.

TypeScript

Parser node types are re-exported from stream-markdown-parser, and Vue 2 specific mapping types are available from markstream-vue2 itself:

import type { CustomComponents, ParsedNode } from 'markstream-vue2'

Related Packages

@ashlesss/markstream-vue

Streaming-friendly Vue 3 Markdown renderer for docs sites, AI chat UIs, and larg...

1,121 0
markstream-vue

Vue/Nuxt streaming Markdown renderer for AI chat, LLM token streams, SSE/WebSock...

636,231 3,040
vue-renderer-markdown-monaco

A Vue 3 component that renders Markdown string content as HTML, supporting custo...

1,952 3,033
@comark/nuxt

Nuxt module for Comark. Render Markdown with components at runtime, with auto-im...

390,704 1,080
@comark/vue

Vue 3 renderer for Comark. Render Markdown with components at runtime, with stre...

1,255,538 1,080

Version History

Version Released License
2.0.20 MIT
2.0.19 MIT
2.0.18 MIT
2.0.17 MIT
2.0.16 MIT
Pre-releases (25)
Version Released License
0.1.0-beta.4 MIT
0.1.0-beta.3 MIT
0.1.0-beta.2 MIT
0.1.0-beta.1 MIT
0.0.46-beta.1 MIT