Skip to content

XMarkdown (External)

使用import { MarkdownRenderer } from 'x-markdown-vue' import 'x-markdown-vue/style'
文档
Edit this pageChangelogFeedback

Introduction ​

x-markdown-vue is a standalone Markdown rendering library extracted from vue-element-plus-x, purpose-built for rich text display and streaming output in AI chat scenarios.

✨ Features ​

  • 🚀 Streaming Rendering — Real-time output animation for AI chat, with per-token fade-in effects
  • 📝 GitHub Flavored Markdown — Full GFM support (tables, task lists, strikethrough, etc.)
  • 🎨 Syntax Highlighting — Powered by Shiki with 100+ languages and multiple themes
  • 🧮 LaTeX Math — Inline $...$ and block $$...$$ math formulas
  • 📊 Mermaid Diagrams — Flowcharts, sequence diagrams, Gantt charts, class diagrams, and more
  • 🌗 Dark Mode — Built-in light/dark theme support
  • 🔌 Highly Customizable — Custom render slots, custom attributes, custom code block renderers
  • 🎭 Plugin System — remark and rehype plugin extensions
  • 🔒 Secure — Optional HTML sanitization to prevent XSS attacks

Starting from v2.0.0, vue-element-plus-x no longer bundles Typewriter / XMarkdown / XMarkdownAsync. Install x-markdown-vue separately.

Installation ​

bash
# pnpm (recommended)
pnpm add x-markdown-vue

# npm
npm install x-markdown-vue

# yarn
yarn add x-markdown-vue

Optional Dependencies ​

x-markdown-vue uses optional peer dependencies for extra features:

bash
# Syntax highlighting (Shiki)
pnpm add shiki shiki-stream

# Mermaid diagrams
pnpm add mermaid

# LaTeX math formulas (also requires importing the CSS)
pnpm add katex

💡 Tip

If shiki / shiki-stream are not installed, code blocks will fall back to plain text rendering.

Code Examples ​

Basic Usage ​

Loading...

Use MarkdownRenderer to render static Markdown content with GFM, task lists, tables, and syntax highlighting.

Streaming Animation ​

Loading...

Enable enable-animate to add a fade-in animation for each newly appended token — ideal for AI streaming output.

Dark Mode ​

Light
Loading...

Use the is-dark prop to toggle between light and dark themes. Shiki syntax highlighting themes switch automatically.

Code Block Configuration ​

Max Height:
Loading...

Configure code block header visibility, max height, and sticky header behavior.

Sticky Code Header with BubbleList ​

Place MarkdownRenderer inside BubbleList's #content slot so BubbleList becomes the scroll container. When the list is scrolled, the code block header sticks to the top of the list's visible area — never occluded by the page navbar.

💡 Scroll the list down — the code block header will stick to the top of the BubbleList viewport, not the page top.

Place MarkdownRenderer inside BubbleList's #content slot so BubbleList acts as the scroll container. When the list is scrolled, the code block language label and action bar stick to the top of BubbleList's visible area — not the page viewport — so the document navbar never occludes it.

LaTeX Math Formulas ​

Install katex and import its CSS:

ts
import 'katex/dist/katex.min.css';
Loading...

Enable LaTeX math with enable-latex. Install katex and import its CSS file.

Mermaid Diagrams ​

Install mermaid first: pnpm add mermaid

Loading...

Enable enable-mermaid to render flowcharts, sequence diagrams, and more. Install mermaid first.

Custom Code Block Actions ​

Pass a code-block-actions array to add custom buttons to code block headers. Use the show callback to conditionally display buttons per language.

onClick receives a CodeBlockSlotProps object:

PropertyTypeDescription
languagestringCode language
codestringCode content
copy(text: string) => voidCopy function
copiedbooleanWhether copied
collapsedbooleanWhether collapsed
toggleCollapse() => voidToggle collapse
Loading...

Pass a code-block-actions array to add custom buttons to code block headers. Use show to conditionally display buttons.

Custom Mermaid Actions ​

Pass a mermaid-actions array to add custom buttons to the Mermaid diagram toolbar.

onClick receives a MermaidSlotProps object:

PropertyTypeDescription
showSourceCodebooleanWhether showing source code view
svgstringRendered SVG string
rawContentstringRaw Mermaid source code
isLoadingbooleanWhether currently rendering
zoomIn() => voidZoom in
zoomOut() => voidZoom out
reset() => voidReset zoom
fullscreen() => voidFullscreen
toggleCode() => voidToggle source/diagram view
copyCode() => Promise<void>Copy source code
download() => voidDownload SVG
Loading...

Pass a mermaid-actions array to add custom buttons to the Mermaid diagram toolbar.

Custom Code Block Renderer ​

Loading...

Use code-x-render to replace the default code block renderer for specific languages with a fully custom component.

Custom Attributes ​

Loading...

Add custom HTML attributes to any Markdown element via custom-attrs. Useful for styling or behavior customization.

Custom Slots ​

Supported slot names:

SlotDescription
heading / h1 ~ h6Headings
code / inline-code / block-codeCode
blockquoteBlockquote
list / ul / ol / li / list-itemLists
table / thead / tbody / tr / td / thTables
aLinks
imgImages
p / strong / emInline elements
Any standard HTML tag name—
Loading...

Override Markdown element rendering using named slots for complete control over the HTML output.

Custom Table with el-table ​

Use the #table slot to replace all GFM tables in Markdown with el-table. The hast node passed to the slot contains the full table structure — a helper extracts columns and rows, then feeds them to el-table.

Loading...

Override Markdown GFM table rendering via the #table slot. The slot exposes children (a function returning a VNode array) — recursively walk <thead> / <tbody> to collect columns and rows, then render with el-table for borders, stripes, and more.

Custom Code Block Components (el-table & my-echarts) ​

Define your own "language" tags via code-x-render. Write JSON inside a fenced code block, set the language to el-table or my-echarts, and the renderer maps each block to a real Vue component.

  • el-table — parses JSON { columns, rows } and renders as an Element Plus table
  • my-echarts — parses an ECharts option JSON and renders as an interactive chart
Loading...

Use code-x-render to render specific code block languages as Vue components:

  • el-table blocks — render JSON data as an Element Plus table
  • my-echarts blocks — render ECharts JSON config as an interactive chart

Plugin System ​

Extend the parsing pipeline with remark/rehype plugins:

ts
import remarkEmoji from 'remark-emoji';
import rehypeSlug from 'rehype-slug';

const remarkPlugins = [remarkEmoji];
const rehypePlugins = [rehypeSlug];
vue
<MarkdownRenderer
  :markdown="content"
  :remark-plugins="remarkPlugins"
  :rehype-plugins="rehypePlugins"
/>

Security ​

Enable sanitize to strip unsafe HTML before rendering, preventing XSS:

vue
<MarkdownRenderer
  :markdown="content"
  :sanitize="true"
  :sanitize-options="{ allowedTags: ['b', 'i', 'em', 'strong', 'a'] }"
/>

Streaming Custom Code Blocks (with Skeleton Placeholder) ​

A real-world AI streaming scenario: while the JSON is being assembled, show an el-skeleton placeholder; once the data becomes parseable, swap to the real el-table / el-form / my-echarts component.

Loading...

A real-world AI streaming scenario: while the JSON inside an `el-table` / `el-form` / `my-echarts` code block is still being assembled, show an el-skeleton placeholder; once the JSON becomes valid, swap to the actual component.

The trick: inside code-x-render, try JSON.parse(props.raw.content). Parse fails → skeleton; parse succeeds → real component. Combined with streaming updates this naturally produces a "skeleton → content" transition.

API ​

Props ​

PropTypeDefaultDescription
markdownstring''Markdown text content
allow-htmlbooleanfalseAllow raw HTML in content
enable-latexbooleantrueEnable LaTeX math rendering
enable-animatebooleanfalseEnable streaming animation
enable-breaksbooleantrueConvert single newlines to <br>
enable-gfmbooleantrueEnable GitHub Flavored Markdown
enable-shikibooleantrueEnable Shiki syntax highlighting
enable-mermaidbooleantrueEnable Mermaid diagram rendering
is-darkbooleanfalseDark mode
shiki-theme[BuiltinTheme, BuiltinTheme]['vitesse-light', 'vitesse-dark']Shiki light/dark themes
show-code-block-headerbooleantrueShow code block header bar
sticky-code-block-headerbooleanfalseSticky code block header
code-max-heightstringundefinedMax height of code blocks, e.g. '300px'
code-block-actionsCodeBlockAction[][]Custom code block action buttons
mermaid-actionsMermaidAction[][]Custom Mermaid action buttons
mermaid-configobject{}Mermaid initialization config
code-x-renderobject{}Custom code block render functions
custom-attrsCustomAttrs{}Custom element attributes
remark-pluginsPluggableList[]remark plugins (run after built-ins)
remark-plugins-aheadPluggableList[]remark plugins (run before built-ins)
rehype-pluginsPluggableList[]rehype plugins (run after built-ins)
rehype-plugins-aheadPluggableList[]rehype plugins (run before built-ins)
rehype-optionsobject{}rehype processor options
sanitizebooleanfalseEnable HTML sanitization (XSS prevention)
sanitize-optionsSanitizeOptions{}Sanitization options

CodeBlockAction Type ​

ts
interface CodeBlockAction {
  key: string;
  icon?: Component | FunctionalComponent | string;
  title?: string;
  onClick?: (props: CodeBlockSlotProps) => void;
  disabled?: boolean;
  class?: string;
  style?: Record<string, string>;
  show?: (props: CodeBlockSlotProps) => boolean;
}

MermaidAction Type ​

ts
interface MermaidAction {
  key: string;
  icon?: Component | FunctionalComponent | string;
  title?: string;
  onClick?: (props: MermaidSlotProps) => void;
  disabled?: boolean;
  class?: string;
  style?: Record<string, string>;
  show?: (props: MermaidSlotProps) => boolean;
}