
beautiful-mermaid is a JavaScript library that converts Mermaid diagrams into production-ready SVGs or terminal-friendly ASCII/Unicode art.
It supports 15 built-in themes and runs anywhere JavaScript executes, browsers, Node.js, Bun, Deno, or terminal, with zero DOM dependencies.
Features:
- Dual Output Modes: Renders to SVG for rich UIs or ASCII/Unicode for terminals and plain text environments.
- Built-in Themes: 15+ themes including Tokyo Night, Catppuccin, Nord, Dracula, and GitHub Dark/Light.
- Live Theme Switching: Uses CSS custom properties on the SVG element for instant theme changes.
- Shiki Compatibility: Extracts diagram colors from any VS Code theme in Shiki’s registry for consistent editor integration.
- Mono Mode: Generates coherent diagrams from just two colors (background and foreground) using automated color derivation.
- Five Diagram Types: Supports flowcharts, state diagrams, sequence diagrams, class diagrams, and ER diagrams.
- Ultra-Fast Performance: Renders over 100 diagrams in under 500ms.
Use Cases:
- AI Coding Assistants: Display data flows, state machines, and architecture diagrams directly in chat interfaces where users need instant visual context.
- CLI Developer Tools: Render diagrams as ASCII art in terminal output for command-line applications, log viewers, and debugging tools.
- Documentation Generators: Produce themed SVG diagrams that match your documentation site’s color scheme.
- Terminal-Based IDEs: Show project structure, call graphs, and dependency trees as Unicode diagrams in Vim, Emacs, or other text-based editors.
How To Use It:
1. Install the beautiful-mermaid package and import it into your project:
# NPM $ npm install beautiful-mermaid # PNPM $ pnpm install beautiful-mermaid # BUN $ bun add beautiful-mermaid
import { renderMermaid, THEMES, renderMermaidAscii } from 'beautiful-mermaid'2. For browser environments without a bundler, load the beautiful-mermaid.browser.global.js script file from the dist folder or from a CDN:
The browser bundle exposes
renderMermaid,renderMermaidAscii,THEMES,DEFAULTS, andfromShikiThemeon the globalbeautifulMermaidobject.
<script src="https://unpkg.com/beautiful-mermaid/dist/beautiful-mermaid.browser.global.js"></script>
const { renderMermaid, THEMES } = beautifulMermaid;3. Render a Mermaid diagram to SVG with default styling.
// Define a simple flowchart
const diagram = `
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Action]
B -->|No| D[End]
`
// Render to SVG string
const svg = await renderMermaid(diagram)
// The svg variable now contains a complete SVG string
// you can inject into the DOM or save to a file
document.getElementById('container').innerHTML = svg4. For terminal environments, use renderMermaidAscii:
// Render using Unicode box-drawing characters (default)
const unicode = renderMermaidAscii(`graph LR; A --> B --> C`)
console.log(unicode)
// Output:
// ┌───┐ ┌───┐ ┌───┐
// │ │ │ │ │ │
// │ A │────►│ B │────►│ C │
// │ │ │ │ │ │
// └───┘ └───┘ └───┘
// Render using pure ASCII for maximum compatibility
const ascii = renderMermaidAscii(`graph LR; A --> B`, { useAscii: true })
console.log(ascii)
// Output:
// +---+ +---+
// | | | |
// | A |---->| B |
// | | | |
// +---+ +---+5. Apply the following themes to the diagrams: zinc-light, zinc-dark, tokyo-night, tokyo-night-storm, tokyo-night-light, catppuccin-mocha, catppuccin-latte, nord, nord-light, dracula, github-light, github-dark, solarized-light, solarized-dark, one-dark.
// Render with Tokyo Night theme const svg = await renderMermaid(diagram, THEMES['tokyo-night'])
6. Creating your own themes. The theming system requires only two colors at minimum.
// Mono mode: just background and foreground
const customTheme = {
bg: '#0f0f0f', // Dark background
fg: '#e0e0e0', // Light foreground
}
const svg = await renderMermaid(diagram, customTheme)7. The library automatically derives all other colors (borders, fills, labels) using color-mix(). For richer themes, add optional enrichment colors:
const richTheme = {
bg: '#0f0f0f',
fg: '#e0e0e0',
accent: '#ff6b6b', // Arrow heads and highlights
line: '#888888', // Edge connectors
muted: '#666666', // Secondary text
surface: '#1a1a1a', // Node fill tint
border: '#333333', // Node stroke
}
const svg = await renderMermaid(diagram, richTheme)8. All theme colors are CSS custom properties on the SVG element. Change themes without re-rendering:
const svg = await renderMermaid(diagram, THEMES['github-light'])
// Insert SVG into DOM
const container = document.getElementById('diagram')
container.innerHTML = svg
// Switch to dark theme instantly
const svgElement = container.querySelector('svg')
svgElement.style.setProperty('--bg', '#0d1117')
svgElement.style.setProperty('--fg', '#c9d1d9')
svgElement.style.setProperty('--accent', '#4493f8')
// The diagram updates immediately without re-parsing Mermaid9. Use any VS Code theme from Shiki’s registry:
import { getSingletonHighlighter } from 'shiki'
import { renderMermaid, fromShikiTheme } from 'beautiful-mermaid'
// Load a Shiki theme (e.g., Vitesse Dark)
const highlighter = await getSingletonHighlighter({
themes: ['vitesse-dark', 'rose-pine']
})
// Extract diagram colors from the theme
const colors = fromShikiTheme(highlighter.getTheme('vitesse-dark'))
// Render with matching colors
const svg = await renderMermaid(diagram, colors)10. All available options:
renderMermaid
bg(string): Background color. Defaults to#FFFFFF. Accepts any valid CSS color value.fg(string): Foreground color for text and primary elements. Defaults to#27272A. Accepts any valid CSS color value.line(string, optional): Color for edge connectors and lines. If omitted, derived fromfgat 30% opacity mixed intobg.accent(string, optional): Color for arrow heads and highlighted elements. If omitted, derived fromfgat 50% opacity mixed intobg.muted(string, optional): Color for secondary text and labels. If omitted, derived fromfgat 60% opacity mixed intobg.surface(string, optional): Background tint for node fills. If omitted, derived fromfgat 3% opacity mixed intobg.border(string, optional): Color for node strokes and borders. If omitted, derived fromfgat 20% opacity mixed intobg.font(string): Font family for all text. Defaults toInter. Provide any CSS font-family string.transparent(boolean): Render SVG with transparent background instead of thebgcolor. Defaults tofalse.padding(number): Canvas padding in px. Defaults to40.nodeSpacing(number): Horizontal spacing between sibling nodes. Defaults to24.layerSpacing(number): Vertical spacing between layers. Defaults to40.componentSpacing(number): Spacing between disconnected components. Defaults to24.thoroughness(number): Crossing minimization trials (1-7, higher = better but slower). Defaults to3.
renderMermaidAscii
useAscii(boolean): Whentrue, uses ASCII characters (+,-,|). Whenfalse(default), uses Unicode box-drawing characters (┌,─,│).paddingX(number): Horizontal spacing between nodes. Defaults to5.paddingY(number): Vertical spacing between nodes. Defaults to5.boxBorderPadding(number): Padding inside node boxes. Defaults to1.colorMode: ‘none’, ‘auto’, ‘ansi16’, ‘ansi256’, ‘truecolor’, or ‘html’.theme: Override default colors for ASCII output
Alternatives
- Mermaid.js: The original Mermaid renderer. Provides more diagram types and mature ecosystem. Requires DOM and has heavier dependencies.
- Kroki: Server-side diagram rendering API supporting multiple syntax formats including Mermaid.
FAQs:
Q: Can I use beautiful-mermaid in a Next.js server component?
A: Yes. Call renderMermaid in server components and pass the SVG string to the client. Make sure to mark the component as async since renderMermaid returns a Promise.
Q: How do I render diagrams with a transparent background for overlaying on images?
A: Set the transparent option to true when calling renderMermaid.
Q: Why do my ASCII diagrams look broken in some terminals?
A: Unicode box-drawing characters require Unicode support. If your terminal doesn’t render them correctly, pass { useAscii: true } to renderMermaidAscii. This uses basic ASCII characters that work everywhere. This uses basic ASCII characters that work everywhere.
Q: Can I dynamically change colors on an already-rendered SVG?
A: Yes. All colors are CSS custom properties on the SVG element. Use svgElement.style.setProperty('--bg', '#new-color') to update themes without re-rendering. This works for any of the color properties: --bg, --fg, --line, --accent, --muted, --surface, --border.
Q: What happens if I provide a color for accent but not for line?
A: The library uses your custom accent color for arrow heads and highlights. For line, it falls back to the derived value (30% of fg mixed into bg). You can mix and match custom colors with auto-derived ones based on what you want to control.
Changelog:
v1.1.2 (02/26/2026)
- Full support for Mermaid’s xychart-beta syntax — bar charts, line charts, and combinations
v1.0.1/2 (02/24/2026)
- Centering: contentAlignment H_CENTER V_CENTER for subgraphs
- Node placement: BALANCED fixed alignment at root and subgraph level
- Edge spacing: optimized edgeEdge, edgeEdgeBetweenLayers, edgeNodeBetweenLayers
- High-degree nodes: special treatment for nodes with 8+ connections
- Post-compaction: LEFT_RIGHT_CONSTRAINT_LOCKING at root level
- Model order: NODES_AND_EDGES preservation at root level
- Post-processing step that snaps same-layer nodes to uniform flow-axis positions, fixing the visual stagger caused by ELK’s orthogonal edge routing. Uses single-linkage clustering for accurate grouping across any fan-out size.
- Fan-out/fan-in edges now share common trunk segments with subgraph-aware junction placement.
- Bugfixes
v1.0.0 (02/23/2026)
- ELK.js replaces dagre — fully synchronous layout via FakeWorker bypass, better edge routing and subgraph handling
- Shape-aware edge clipping — edges terminate at actual shape boundaries (e.g. diamond vertices), not bounding boxes
- New layout options — nodeSpacing, layerSpacing, componentSpacing, thoroughness for fine-grained control
- Disconnected component support — graphs with unconnected subgraphs now lay out properly
- Per-subgraph direction overrides — nested subgraphs can have independent LR/TD/BT/RL direction
- <br> tags in node labels, edge labels, and subgraph headers — line breaks work everywhere
- Inline formatting — <b>, <i>, <u>, <s> tags render as bold/italic/underline/strikethrough in SVG
- Variable-width text measurement — character-class buckets (narrow, wide, CJK, emoji) instead of fixed-ratio estimation
- ANSI color modes — none, ansi16, ansi256, truecolor, and html (for browser rendering)
- AsciiTheme type — customize colors per role: fg, border, line, arrow, corner, junction
- colorMode: ‘auto’ — auto-detects terminal capabilities
- 12+ distinct node shapes in terminal output: rectangle, rounded, diamond, circle, hexagon, stadium, cylinder, doublecircle, subroutine, asymmetric, trapezoid, state-start, state-end
- Edge bundling — fan-in/fan-out patterns merge into visual junctions (TD direction)
- Multi-line labels in both nodes and edges
- Multi-section boxes for class diagrams (name / attributes / methods) and ER diagrams
- Canvas role tracking — each character tagged with semantic role for accurate colorization
- Diagonal line validation — assertNoDiagonals() for test assertions
- Semantic data attributes on all elements (data-id, data-from, data-to, data-style, data-label)
- Improved arrow markers — combined fill + stroke for crisp rendering at small sizes
- Better edge label pills — increased stroke width, improved contrast
- dagre removed — replaced by ELK.js (API unchanged, layout results differ)
- tsup.config.ts removed (no longer bundled separately)







