Extensions

Add syntax highlighting, mathematics, and diagrams only when your application needs them.

vue-stream-markdown works without any rich-renderer package. Code remains readable source, math stays ordinary Markdown text, and Mermaid fences remain code blocks until the corresponding extension is supplied.

Extension factories receive their renderer options and return instances for the extensions prop.

Complete example

<script setup lang="ts">
import { beautifulMermaid } from '@stream-markdown/beautiful-mermaid'
import { code } from '@stream-markdown/code'
import { math } from '@stream-markdown/math'
import { mermaid } from '@stream-markdown/mermaid'
import { Markdown, MarkdownProvider } from 'vue-stream-markdown'
import 'katex/dist/katex.min.css'

const extensions = {
  code: code({
    theme: ['github-light', 'github-dark'],
    langs: ['typescript', 'vue'],
  }),
  math: math({
    config: { throwOnError: false },
  }),
  beautifulMermaid: beautifulMermaid({
    theme: ['github-light', 'github-dark'],
  }),
  mermaid: mermaid({
    theme: ['neutral', 'dark'],
  }),
}
</script>

<template>
  <MarkdownProvider :extensions="extensions">
    <Markdown :content="content" />
  </MarkdownProvider>
</template>

Create extension instances once. For a chat or message list, pass them through MarkdownProvider so every message can share the same configuration:

<script setup lang="ts">
import { code } from '@stream-markdown/code'
import { Markdown, MarkdownProvider } from 'vue-stream-markdown'

const extensions = { code: code() }
</script>

<template>
  <MarkdownProvider :extensions="extensions">
    <Markdown v-for="message in messages" :key="message.id" :content="message.content" />
  </MarkdownProvider>
</template>

An instance can replace one provider extension or disable it with false:

<Markdown :extensions="{ code: false }" />

Code

Install @stream-markdown/code to enable Shiki highlighting:

pnpm add @stream-markdown/code
import type { CodeExtensionOptions } from '@stream-markdown/code'
import { code } from '@stream-markdown/code'

const options: CodeExtensionOptions = {
  theme: ['vitesse-light', 'vitesse-dark'],
  langs: ['typescript', 'vue'],
  langAlias: { 'custom-lang': 'typescript' },
  codeToTokenOptions: {
    includeExplanation: false,
  },
}

const codeExtension = code(options)

Math

Install @stream-markdown/math to add both Comark math parsing and KaTeX rendering:

pnpm add @stream-markdown/math
import type { MathExtensionOptions } from '@stream-markdown/math'
import { math } from '@stream-markdown/math'

const options: MathExtensionOptions = {
  config: {
    throwOnError: false,
    macros: {
      '\\RR': '\\mathbb{R}',
    },
  },
}

const mathExtension = math(options)

For local package loading, import KaTeX CSS in your application:

import 'katex/dist/katex.min.css'

The extension adds both math parsing and KaTeX rendering. Without it, math-like source remains ordinary text.

Mermaid

The standard Mermaid renderer supports every diagram type supported by your Mermaid version:

pnpm add @stream-markdown/mermaid
import type { MermaidExtensionOptions } from '@stream-markdown/mermaid'
import { mermaid } from '@stream-markdown/mermaid'

const options: MermaidExtensionOptions = {
  theme: ['neutral', 'dark'],
  config: {
    securityLevel: 'strict',
    flowchart: { curve: 'basis' },
  },
}

const mermaidExtension = mermaid(options)

Beautiful Mermaid

Install the lightweight Beautiful Mermaid renderer independently:

pnpm add @stream-markdown/beautiful-mermaid
import type { BeautifulMermaidExtensionOptions } from '@stream-markdown/beautiful-mermaid'
import { beautifulMermaid } from '@stream-markdown/beautiful-mermaid'

const options: BeautifulMermaidExtensionOptions = {
  theme: ['github-light', 'github-dark'],
  config: { padding: 12 },
}

const beautifulMermaidExtension = beautifulMermaid(options)

You can configure both diagram extensions at once:

const extensions = {
  beautifulMermaid: beautifulMermaid(),
  mermaid: mermaid(),
}

The renderer tries Beautiful Mermaid only for diagram types it supports, then falls back to Mermaid. If Mermaid is omitted, unsupported diagrams stay as code blocks.

Custom error components

Provider error components belong to their extension factory:

import DiagramError from './diagram-error.vue'

const extensions = {
  mermaid: mermaid({ errorComponent: DiagramError }),
  math: math({ errorComponent: DiagramError }),
}

CDN loading

CDN configuration also belongs to each extension rather than <Markdown>:

const cdnOptions = {
  getUrl(module: string, version: string) {
    if (module === 'katex-css')
      return `https://esm.sh/katex@${version}/dist/katex.min.css`
    return `https://esm.sh/${module}@${version}`
  },
}

const extensions = {
  code: code({ cdnOptions }),
  math: math({ cdnOptions }),
  beautifulMermaid: beautifulMermaid({ cdnOptions }),
  mermaid: mermaid({ cdnOptions }),
}

You can also set baseUrl and provider switches such as shiki, katex, mermaid, or beautifulMermaid. Local dependencies remain the default when no CDN URL is configured.