Diagram as a Code Using Mermaid
Monday, September 15, 2025
Today I need to visualize a data flow using diagram. I started with my go-to tools, Draw.io. It's quickly getting complicated. I need to move elements around, ensure the arrows are still correct, update the formatting, and soon I can see it taking a lot of time.
I decided to use a different approach. In KCDC, there's a session about diagram and I remember the tool is Mermaid, so I decided to learn it. And within minutes, I'm able to create very dynamic sequence diagram and entity relation diagram in markdown file.
With Mermaid Plugin in VS Code
This is how I originally have it. Basically install Mermaid plugin for VS Code. Then on the markdown, add the following text:
```mermaid
sequenceDiagram
participant user as User
participant web as Web UI
participant api as API
user->>web: GET /
web->>user: return <html>
user-->>api: GET /api/resource
api-->>user: return {json}
```
Show preview on VS Code and the diagram will be rendered.
For more information: https://www.mermaidchart.com/
In Nuxt Content Markdown using NPM Package
For the purpose of showing the diagram in this blog, I had to approach it differently as it will be rendered as html. Instead of plugin, I installed the npm package.
yarn add mermaid
It actual does server side rendering, but since I'm not going to have a server, I need a client side rendering. Good thing is there's a workaround: https://github.com/nuxt/content/issues/1866. Thank to all the folks that contribute to the solutions!
First, we need to create a client side plugin under <app>/plugins/mermaid.client.ts with the following content:
import mermaid from 'mermaid'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.provide('mermaid', () => mermaid)
})
Next, we need a custom component, let say <app>/components/mermaid.vue:
<script setup lang="ts">
const { $mermaid } = useNuxtApp();
const mermaidContainer = ref<HTMLPreElement | null>(null)
onMounted(async () => {
const { $mermaid } = useNuxtApp();
const mermaidContainer = ref<HTMLPreElement | null>(null)
onMounted(async () => {
if (mermaidContainer.value?.textContent) {
await nextTick()
try {
$mermaid().initialize({ startOnLoad: false, theme: 'default' })
await $mermaid().run({
nodes: [mermaidContainer.value],
})
}
catch (e) {
console.error('Error running Mermaid:', e)
mermaidContainer.value.innerHTML = '⚠️ Mermaid Chart Syntax Error'
}
}
})
</script>
<template>
<pre ref="mermaidContainer" class="mermaid">
<slot mdc-unwrap="p" />
</pre>
</template>
Then, add a type to make typescript happy at <app>/types/mermaid.d.ts:
import type { mermaid } from 'mermaid'
declare module '#app' {
interface NuxtApp {
$mermaid: () => mermaid
}
}
export {}
Finally, on the markdown:
::mermaid
sequenceDiagram
participant user as User
participant web as Web UI
participant api as API
user->>web: GET /
web->>user: return <html>
user-->>api: GET /api/resource
api-->>user: return {json}
::
which renders the diagram:
sequenceDiagram
participant user as User
participant web as Web UI
participant api as API
user->>web: GET /
web->>user: return
user-->>api: GET /api/resource
api-->>user: return {json}
For more information: https://mermaid.js.org/