VitePress
A plot fence in your VitePress pages becomes a chart when VitePress builds the page: the markdown-it plugin writes the chart's SVG into the HTML, so it shows with no script, and it follows VitePress's dark mode.
Install
npm i @devlooped/plotdown linkedom
linkedom gives the plugin a document to draw in while VitePress renders in Node (jsdom works too).
.vitepress/config.mts
import plotdown from "@devlooped/plotdown/markdown-it";
import {defineConfig} from "vitepress";
export default defineConfig({
markdown: {
config: (md) => md.use(plotdown)
}
});
The plugin takes over only plot, oplot and observable-plot fences; every other fence keeps VitePress's Shiki highlighting.
Write a chart
```plot
{
"y": {"grid": true},
"marks": [
{"mark": "barY", "data": [{"species": "Adelie", "mass": 3750}, {"species": "Gentoo", "mass": 5000}], "x": "species", "y": "mass", "fill": "species"},
{"mark": "ruleY", "data": [0]}
]
}
```
The spec lists the marks and options; the playground checks a block as you type.
Check it
vitepress dev docs (or build), then open the page: each block is a <div class="plotdown"> around Plot's SVG. A block with a mistake stays code in <div class="plotdown plotdown-error">, with the reason in <p class="plotdown-message">, and the build goes on.
Notes
- Vue templates: VitePress compiles each page as a Vue template. The plugin sees that (mdit-vue's
env) and writes Plot's<style>as<component is="style">and braces as character references, so a label such as{{ 6 * 7 }}stays text. Force it withmd.use(plotdown, {vue: true}). - Dark mode: the chart draws with
currentColor, so it follows VitePress's toggle. - Errors: VitePress styles only its own code blocks; give
.plotdown-error preand.plotdown-messagea style in your theme's CSS.md.use(plotdown, {strict: true})fails the build instead, andonError: (error) => console.warn(error.message)logs each one. - Titles: a
"title"and a"subtitle"become<p class="plotdown-title">and<p class="plotdown-subtitle">inside the figure, not headings, so they stay out of VitePress's outline and heading style. - Remote data: markdown-it cannot wait, so a block with
{"url": …}data fails at build time even withallowRemote. Put the data inline, or usemode: "client"and the script tag withdata-allow-remote.
Note
Tried with VitePress 1.6.4 (markdown-it 15.0.3) on 2026-11-12.