Skip to content

VitePress integration

VitePress is the easiest way to miss the hard part of diagram rendering. Markdown changes happen on route transitions, not on full page reloads, so wrapper discovery has to survive navigation

Minimal setup

ts
// docs/.vitepress/config.ts
import { defineConfig } from 'vitepress'
import markdownItMermaidEnhanced from 'markdown-it-mermaid-enhanced'

export default defineConfig({
  markdown: {
    config: (md) => {
      md.use(markdownItMermaidEnhanced, {
        theme: 'auto',
        renderEngine: 'mermaidjs',
      })
    },
  },
})
ts
// docs/.vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import 'markdown-it-mermaid-enhanced/styles.css'
import mermaidPlugin from 'markdown-it-mermaid-enhanced/vitepress'

export default {
  extends: DefaultTheme,
  enhanceApp(ctx) {
    mermaidPlugin(ctx, {
      waitFor: 'animation-frame',
    })
  },
} satisfies Theme

What the helper actually does

  • Disables runtime auto-init before loading the browser module
  • Waits for DOM updates after page navigation
  • Retries wrapper discovery while the page is still hydrating
  • Calls initMermaidIt() on the current route root

Available helper options

FieldTypeNotes
rootParentNode | string | () => ParentNode | nullLimits rendering to a scoped container
waitFor'animation-frame' | 'microtask'Picks the DOM update boundary before rendering

Scoped rendering

ts
mermaidPlugin(ctx, {
  root: '.VPDoc',
  waitFor: 'animation-frame',
})

That pattern works well when the surrounding page has other runtime islands that should stay untouched