Overview
CodeInk includes native support for Mermaid , allowing you to create professional diagrams using simple text-based syntax. All diagrams are rendered client-side with full theme support.
Getting Started
Basic Usage
Create diagrams using fenced code blocks with the mermaid or mmd language identifier:
```mermaid
graph TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug]
D --> B
```
Both mermaid and mmd language identifiers are supported and work identically.
Supported Diagram Types
Flowcharts
Create process flows and decision trees:
```mermaid
flowchart LR
A[Square] --> B(Round)
B --> C{Decision}
C -->|Yes| D[Result 1]
C -->|No| E[Result 2]
```
Sequence Diagrams
Visualize interactions between components:
```mermaid
sequenceDiagram
participant User
participant Editor
participant Preview
User->>Editor: Type markdown
Editor->>Preview: Send content
Preview->>Preview: Render HTML
Preview-->>User: Display preview
```
Gantt Charts
Project timelines and schedules:
```mermaid
gantt
title Project Timeline
dateFormat YYYY-MM-DD
section Phase 1
Design :2024-01-01, 30d
Development :2024-02-01, 60d
section Phase 2
Testing :2024-04-01, 30d
Deployment :2024-05-01, 15d
```
Gantt charts have special rendering optimizations in CodeInk for better layout.
More Diagram Types
Mermaid supports many other diagram types:
Class Diagrams UML class relationships and structures
State Diagrams State machines and transitions
Entity Relationship Database schemas and relationships
User Journey User experience flows
Git Graphs Git branch and merge visualization
Pie Charts Simple data visualization
Theme Integration
Automatic Theme Matching
Mermaid diagrams automatically match the application theme:
function getMermaidTheme () : "dark" | "default" {
const theme = document . documentElement . getAttribute ( "data-theme" )
return theme === "light" ? "default" : "dark"
}
mermaid . initialize ({
startOnLoad: false ,
theme: getMermaidTheme (),
securityLevel: "loose" ,
})
Dynamic Theme Updates
When you switch themes, diagrams are automatically re-rendered:
window . addEventListener ( "codeink-theme-change" , () => {
// Clear processed flag from all diagrams
const mermaidNodes = container . querySelectorAll ( ".mermaid[data-processed]" )
for ( const node of mermaidNodes ) {
node . removeAttribute ( "data-processed" )
}
// Trigger re-render
window . dispatchEvent ( new Event ( "mermaid-rerender" ))
})
Rendering System
Lazy Loading
Mermaid is loaded on-demand when the first diagram is encountered:
let mermaidPromise : Promise < typeof mermaidType > | null = null
function getMermaid () {
mermaidPromise ??= import ( "mermaid" ). then (( mod ) => mod . default )
return mermaidPromise
}
This keeps the initial bundle size small and only loads Mermaid when actually needed.
Render Process
Diagrams are rendered asynchronously in the preview pane:
export async function renderMermaidDiagrams ( container : HTMLElement ) {
// Find unprocessed diagram nodes
const unprocessedDivs = container . querySelectorAll ( ".mermaid:not([data-processed])" )
if ( ! unprocessedDivs . length ) return
const mermaid = await getMermaid ()
ensureMermaidInitialized ( mermaid )
// Render all diagrams
await mermaid . run ({
nodes: Array . from ( unprocessedDivs ) as HTMLElement [],
suppressErrors: true ,
})
}
Visibility Detection
Diagrams are only rendered when the preview pane is visible:
function isContainerVisible ( container : HTMLElement ) : boolean {
return container . offsetWidth > 0 && container . offsetHeight > 0
}
if ( ! isContainerVisible ( container )) {
watchForVisibility ( container )
return
}
This prevents rendering errors in hidden containers and improves performance.
Resize Handling
A ResizeObserver watches for visibility changes:
function watchForVisibility ( container : HTMLElement ) {
if ( resizeObserver ) return
resizeObserver = new ResizeObserver (( entries ) => {
for ( const entry of entries ) {
if ( entry . contentRect . width > 0 && entry . contentRect . height > 0 ) {
renderMermaidDiagrams ( container )
}
}
})
resizeObserver . observe ( container )
}
Gantt Chart Optimization
Special Handling
Gantt charts receive special width calculations for optimal display:
const source = node . textContent ?. trimStart () ?? ""
const isGantt = / ^ gantt \b / i . test ( source )
if ( isGantt ) {
node . classList . add ( "mermaid--gantt" )
const parentWidth = node . parentElement ?. getBoundingClientRect (). width
const targetWidth = parentWidth && parentWidth > 0 ? parentWidth : containerWidth
if ( targetWidth > 0 ) {
node . style . width = ` ${ Math . floor ( targetWidth ) } px`
}
}
Custom Configuration
Gantt charts use custom padding and sizing:
mermaid . initialize ({
gantt: {
useMaxWidth: true ,
rightPadding: 75 ,
leftPadding: 75 ,
barHeight: 25 ,
barGap: 4 ,
},
})
Error Handling
Graceful Failures
Rendering errors are caught and logged without breaking the preview:
try {
await mermaid . run ({
nodes: Array . from ( unprocessedDivs ) as HTMLElement [],
suppressErrors: true ,
})
} catch ( error ) {
console . error ( "[Mermaid] Rendering error:" , error )
}
Invalid Mermaid syntax will display an error message in the diagram container.
Integration with Markdown
Code Block Detection
Mermaid code blocks are detected during markdown parsing:
const renderer = {
code ({ text , lang } : Tokens . Code ) {
const normalizedLang = ( lang || "" ). toLowerCase ()
if ( normalizedLang === "mermaid" || normalizedLang === "mmd" ) {
return `<div class="mermaid"> ${ text } </div>`
}
// Handle other languages...
},
}
Render Pipeline
Markdown is parsed and code blocks are converted to <div class="mermaid">
HTML is inserted into the preview pane
renderMermaidDiagrams() finds and processes unrendered diagrams
Mermaid transforms the text into SVG
Singleton Pattern
Only one Mermaid instance and ResizeObserver are created:
let resizeObserver : ResizeObserver | null = null
let initialized = false
let currentTheme : "dark" | "default" | null = null
Conditional Re-initialization
Mermaid is only re-initialized when the theme changes:
function ensureMermaidInitialized ( mermaid : typeof mermaidType ) {
const nextTheme = getMermaidTheme ()
if ( initialized && currentTheme === nextTheme ) return
mermaid . initialize ({ /* config */ })
initialized = true
currentTheme = nextTheme
}
Debounced Rendering
A small delay prevents excessive re-renders:
await new Promise (( resolve ) => setTimeout ( resolve , 50 ))
Source Code Reference
Implementation details can be found in:
/src/scripts/mermaid-renderer.ts - Complete Mermaid rendering logic
/src/lib/markdown.ts - Code block detection and HTML generation
/src/scripts/editor.ts - Theme change handling and re-render triggers
Learn More
For complete Mermaid syntax and examples, visit the official Mermaid documentation .