@mostlylucid/mermaid-enhancements
v1.0.0
Published
Enhance Mermaid.js diagrams with interactive pan/zoom, fullscreen lightbox, export to PNG/SVG, and automatic theme switching
Maintainers
Readme
@mostlylucid/mermaid-enhancements
Enhance Mermaid.js diagrams with interactive pan/zoom, fullscreen lightbox, export capabilities, and automatic theme switching.
Features
- Interactive Pan & Zoom - Navigate large diagrams with smooth mouse wheel zooming and drag-to-pan
- Touch Support - Full touch gesture support (pinch-to-zoom, swipe-to-pan) for mobile devices
- Fullscreen Lightbox - View diagrams in immersive fullscreen mode with integrated toolbar
- Export to PNG/SVG - Download high-quality diagrams (2x pixel ratio for PNG)
- Automatic Theme Switching - Seamlessly adapts to light/dark mode changes
- Customizable Toolbar - Show/hide/toggle individual toolbars or all toolbars at once
- Enhanced Styling - Theme-appropriate borders, drop shadows, and backdrop blur
- Mobile/Cloudflare Optimized - Uses direct DOM node references for better compatibility
- Responsive Design - Works perfectly on mobile, tablet, and desktop
- Keyboard Shortcuts - Press ESC to close lightbox, double-click to zoom
- Accessible - ARIA labels and keyboard navigation support
- TypeScript Support - Full type definitions included
- Zero Configuration - Works out of the box
Installation
npm install @mostlylucid/mermaid-enhancementsPeer Dependencies
This package requires Mermaid.js:
npm install mermaidQuick Start
Basic Usage
import mermaid from 'mermaid';
import { init } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
// Initialize Mermaid with enhancements
await init();Minified Version (Production)
For production use, import the minified version (58% smaller):
import { init } from '@mostlylucid/mermaid-enhancements/min';
import '@mostlylucid/mermaid-enhancements/styles.css';
await init();Size comparison:
- Regular: 23.46 KB
- Minified: 9.78 KB (58.3% smaller)
HTML (via CDN)
<!DOCTYPE html>
<html>
<head>
<!-- Boxicons for control button icons -->
<link href="https://unpkg.com/[email protected]/css/boxicons.min.css" rel="stylesheet">
<!-- Mermaid Enhancements CSS -->
<link rel="stylesheet" href="https://unpkg.com/@mostlylucid/mermaid-enhancements/src/styles.css">
</head>
<body>
<!-- Your Mermaid diagram -->
<div class="mermaid">
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Result 1]
B -->|No| D[Result 2]
</div>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
// Use minified version for production
import { init } from 'https://unpkg.com/@mostlylucid/mermaid-enhancements/dist/index.min.js';
await init();
</script>
</body>
</html>CDN Options:
<!-- unpkg (minified, recommended) -->
<script type="module" src="https://unpkg.com/@mostlylucid/mermaid-enhancements"></script>
<!-- jsdelivr (minified, with version pinning) -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@mostlylucid/[email protected]"></script>
<!-- Direct import -->
<script type="module">
import { init } from 'https://unpkg.com/@mostlylucid/mermaid-enhancements/dist/index.min.js';
await init();
</script>Easy Path
If you just want it to work with the fewest moving parts, use one of these two copy‑paste setups.
Option A — Single HTML file (CDN, no build tools)
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Icons for the toolbar buttons (required unless you override icons) -->
<link href="https://unpkg.com/[email protected]/css/boxicons.min.css" rel="stylesheet">
<!-- Enhancements styles (toolbar, lightbox, etc.) -->
<link rel="stylesheet" href="https://unpkg.com/@mostlylucid/mermaid-enhancements/src/styles.css">
</head>
<body>
<div class="mermaid">
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Result 1]
B -->|No| D[Result 2]
</div>
<script type="module">
// 1) Load Mermaid (v11 or newer)
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
// 2) Load the enhancements (minified build for production)
import { init } from 'https://unpkg.com/@mostlylucid/mermaid-enhancements/dist/index.min.js';
// 3) Initialize once the DOM is ready
window.addEventListener('DOMContentLoaded', async () => {
// Optional: configure before init()
// import { configure } from 'https://unpkg.com/@mostlylucid/mermaid-enhancements/dist/index.min.js';
// configure({ controls: { zoomOut: false } });
await init();
});
</script>
</body>
</html>Notes:
- Include the Boxicons CSS link or provide your own icon classes via
configure({ icons: { ... } }). - Use the minified build (
dist/index.min.js) in production. - Call
init()once after Mermaid is available and the DOM is ready.
Option B — NPM + bundler (Vite/Next/Nuxt/SvelteKit)
// main.ts (or app entry)
import { init } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
// If Mermaid is installed locally
// import mermaid from 'mermaid';
// Call once on the client after the page mounts
(async () => {
// Optional: configure before init()
// import { configure } from '@mostlylucid/mermaid-enhancements';
// configure({ controls: { exportSvg: false } });
await init();
})();Framework hints:
- Next.js/Nuxt: ensure
init()runs client‑side only (e.g., insideuseEffector mounted hook). Avoid running during SSR. - Astro/MDX/Markdown: your diagram containers should have the
mermaidclass. You can callinit()once per page. - Re‑rendering: if your framework rehydrates or replaces the diagram nodes, call
cleanupMermaidEnhancements()before re‑initializing to avoid duplicate toolbars.
API Reference
init()
Initialize Mermaid with all enhancements. This is the main entry point.
import { init } from '@mostlylucid/mermaid-enhancements';
await init();Returns: Promise<void>
initMermaid()
Initialize Mermaid with theme switching support. Called automatically by init().
import { initMermaid } from '@mostlylucid/mermaid-enhancements';
await initMermaid();Features:
- Normalizes code fence blocks
- Sets up theme change listeners
- Handles OS-level theme preferences
- Re-renders diagrams when theme changes
Returns: Promise<void>
enhanceMermaidDiagrams()
Add pan/zoom, fullscreen, and export capabilities to rendered diagrams.
import { enhanceMermaidDiagrams } from '@mostlylucid/mermaid-enhancements';
enhanceMermaidDiagrams();Returns: void
cleanupMermaidEnhancements()
Clean up all pan-zoom instances. Call before re-rendering diagrams or unmounting.
import { cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
cleanupMermaidEnhancements();Returns: void
configure(config)
Configure toolbar buttons and icons globally. Must be called before init().
import { configure } from '@mostlylucid/mermaid-enhancements';
configure({
controls: {
showControls: false, // Hide entire toolbar
fullscreen: true,
zoomIn: true,
zoomOut: false, // Hide zoom out button
reset: true,
exportPng: true,
exportSvg: false // Hide SVG export
},
icons: {
fullscreen: 'fas fa-expand', // Use Font Awesome instead of Boxicons
zoomIn: 'fas fa-plus'
}
});Parameters:
config(EnhancementConfig): Configuration object
Returns: void
hideToolbar(diagramId?)
Hide the toolbar for a specific diagram or all diagrams. Can be called at any time after initialization.
import { hideToolbar } from '@mostlylucid/mermaid-enhancements';
// Hide toolbar for a specific diagram
hideToolbar('diagram-1');
// Hide toolbars for all diagrams
hideToolbar();Parameters:
diagramId(string, optional): The ID of the diagram wrapper. If omitted, hides all toolbars.
Returns: void
showToolbar(diagramId?)
Show the toolbar for a specific diagram or all diagrams. Can be called at any time after initialization.
import { showToolbar } from '@mostlylucid/mermaid-enhancements';
// Show toolbar for a specific diagram
showToolbar('diagram-1');
// Show toolbars for all diagrams
showToolbar();Parameters:
diagramId(string, optional): The ID of the diagram wrapper. If omitted, shows all toolbars.
Returns: void
toggleToolbar(diagramId?)
Toggle the toolbar visibility for a specific diagram or all diagrams. Can be called at any time after initialization.
import { toggleToolbar } from '@mostlylucid/mermaid-enhancements';
// Toggle toolbar for a specific diagram
toggleToolbar('diagram-1');
// Toggle toolbars for all diagrams
toggleToolbar();Parameters:
diagramId(string, optional): The ID of the diagram wrapper. If omitted, toggles all toolbars.
Returns: void
Note: To get the diagram ID, inspect the data-diagram-id attribute on the .mermaid-wrapper element, or capture the return value from enhanceMermaidDiagrams() which returns the generated diagram IDs.
Styling
The package includes a complete CSS file with sensible defaults. Import it in your project:
import '@mostlylucid/mermaid-enhancements/styles.css';Customization
Override CSS variables or classes to customize the appearance:
/* Custom control button colors */
.mermaid-control-btn {
color: #your-color;
}
.mermaid-control-btn:hover {
background: #your-hover-color;
}
/* Custom lightbox background */
.mermaid-lightbox {
background: rgba(0, 0, 0, 0.95);
}Theme Switching
The package automatically detects and responds to theme changes through multiple methods:
1. Custom Events
Dispatch custom events to trigger theme changes:
// Switch to dark theme
document.body.dispatchEvent(new Event('dark-theme-set'));
// Switch to light theme
document.body.dispatchEvent(new Event('light-theme-set'));2. Global State
Set a global theme state:
window.__themeState = 'dark'; // or 'light'
await initMermaid();3. LocalStorage
The package checks localStorage.theme:
localStorage.theme = 'dark'; // or 'light'4. CSS Class
Add a dark class to the <html> element:
document.documentElement.classList.add('dark');5. OS Preference
Automatically detects system-level dark mode preference via prefers-color-scheme.
Toolbar Customization
Configure which buttons appear in the toolbar. All configurations are global and affect all diagrams on the page.
Hide Entire Toolbar
import { configure, init } from '@mostlylucid/mermaid-enhancements';
configure({
controls: {
showControls: false // Hide all toolbars
}
});
await init();Hide Button Groups
configure({
controls: {
export: false, // Hide both PNG and SVG export buttons
fullscreen: false // Hide fullscreen button
}
});Granular Button Control
configure({
controls: {
fullscreen: true,
zoomIn: true,
zoomOut: true,
reset: false, // Hide reset button
exportPng: true,
exportSvg: false // Hide SVG export, keep PNG
}
});
await init();Custom Icon Library
By default, Boxicons are used. You can configure different icon classes:
configure({
icons: {
fullscreen: 'fas fa-expand',
zoomIn: 'fas fa-plus',
zoomOut: 'fas fa-minus',
reset: 'fas fa-undo',
exportPng: 'fas fa-image',
exportSvg: 'fas fa-code'
}
});Control Buttons
Each diagram gets the following controls (when enabled):
| Action | Description | |--------|-------------| | Fullscreen | Open diagram in lightbox with close button on far right | | Zoom In | Increase zoom level | | Zoom Out | Decrease zoom level | | Reset | Reset zoom and position to default | | Export PNG | Download as high-quality PNG (2x pixel ratio) | | Export SVG | Download as vector SVG file |
Note: Panning is always enabled by default (drag to pan). In lightbox mode, a close button (✕) appears on the far right of the toolbar.
Framework Integration
React
import { useEffect } from 'react';
import { init, cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
function MermaidDiagram({ chart }: { chart: string }) {
useEffect(() => {
init();
return () => cleanupMermaidEnhancements();
}, [chart]);
return (
<div className="mermaid">
{chart}
</div>
);
}Vue
<template>
<div class="mermaid">
{{ chart }}
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { init, cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
const props = defineProps(['chart']);
onMounted(async () => {
await init();
});
onUnmounted(() => {
cleanupMermaidEnhancements();
});
</script>Svelte
<script>
import { onMount, onDestroy } from 'svelte';
import { init, cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
export let chart;
onMount(async () => {
await init();
});
onDestroy(() => {
cleanupMermaidEnhancements();
});
</script>
<div class="mermaid">
{@html chart}
</div>Development
Run Demo
npm install
npm run devThis will start a local server and open the demo page at http://localhost:3000.
Build
npm run buildTypeScript
Full TypeScript support is included:
import type { PanZoomInstance, Theme, ExportFormat } from '@mostlylucid/mermaid-enhancements';
// Types are automatically availableContributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This is free and unencumbered software released into the public domain. See LICENSE for details.
Acknowledgments
Built with:
- Mermaid.js - Diagram generation
- svg-pan-zoom - Pan and zoom functionality
- html-to-image - Export capabilities
- Boxicons - Icon library
Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
Known Issues & Workarounds
These are the most common integration issues and how to fix them quickly.
1) Toolbar icons are missing
- Symptom: buttons show empty squares or no icons.
- Cause: Boxicons CSS not loaded, or you use a different icon set.
- Fix:
- Add Boxicons to the page:
<link href="https://unpkg.com/[email protected]/css/boxicons.min.css" rel="stylesheet"> - Or provide your own icon classes before
init():import { configure } from '@mostlylucid/mermaid-enhancements'; configure({ icons: { fullscreen: 'fas fa-expand', zoomIn: 'fas fa-plus', zoomOut: 'fas fa-minus', reset: 'fas fa-undo', exportPng: 'fas fa-file-image', exportSvg: 'fas fa-file-code' } });
- Add Boxicons to the page:
2) Styles look off or toolbar overlaps
- Ensure you import the library CSS once:
import '@mostlylucid/mermaid-enhancements/styles.css'; - If you have strict CSS resets, ensure
.mermaid-lightbox,.mermaid-controls, and.mermaid-containeraren’t unintentionally overridden.
3) Nothing happens after calling init()
- Verify Mermaid v11+ is present before
init(). - Run client-side only (SSR frameworks):
- Next.js: call inside
useEffector a dynamic component withssr: false. - Nuxt: call in
onMounted.
- Next.js: call inside
- If your framework replaces DOM nodes post-mount, call:
import { cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements'; cleanupMermaidEnhancements(); await init();
4) Double toolbars or duplicated pan/zoom
- Cause: re-initializing without cleanup.
- Fix: call
cleanupMermaidEnhancements()before re-rendering/re-initializing.
5) Theme doesn’t switch with OS / site toggle
- Ensure you’re not re-initializing Mermaid on every theme change manually; the library listens to
prefers-color-scheme. - If you have a custom theme toggle that changes a
data-themeor class, call a debounced re-render:// Example: after your site theme toggles await init(); // library re-renders diagrams respecting the new theme
6) Export to PNG/SVG fails
- Check the browser console for CORS errors. Cross-origin images/fonts in your diagram labels can block canvas export.
- Try same-origin fonts and images, or set permissive CORS headers.
- Very large diagrams may run out of memory; zoom in before exporting, or prefer SVG export which is lighter.
7) Mobile pinch/zoom is jumpy
- Some mobile layouts add nested transform/scroll containers. Ensure the
.mermaid-containeris not inside an element that intercepts touch actions. Add:.mermaid-container, .mermaid-container * { touch-action: pinch-zoom; }
8) Performance on extremely large diagrams
- Pan/zoom is enabled, but massive SVGs can be heavy.
- Tips:
- Prefer
flowchartovergraphwhere possible. - Collapse subgraphs.
- Use the lightbox to view fullscreen (less layout thrash).
- Prefer
9) Mermaid version mismatch
- Ensure you’re using Mermaid 11 or newer. Pin versions when using a CDN:
<script type="module"> import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; </script>
10) Shadow DOM or MDX/Markdown renderers
- If your diagrams render inside Shadow DOM or are injected after page load, call
init()after they appear. - For MDX/Markdown engines that hydrate, use cleanup + init as shown above.
11) Content Security Policy (CSP)
- If your site blocks inline styles or data URLs, exporting may fail. Ensure your CSP allows:
img-src 'self' data:style-srcpermitting necessary inline styles or add a nonce that your bundler/framework applies to injected styles.
12) Controlling the toolbar programmatically
- You can show/hide at runtime:
import { hideToolbar, showToolbar, toggleToolbar } from '@mostlylucid/mermaid-enhancements'; hideToolbar(); // all diagrams // hideToolbar('my-diagram-id'); // specific diagram if you provided ids
Troubleshooting
Controls not appearing
Make sure you've included Boxicons:
<link href="https://unpkg.com/[email protected]/css/boxicons.min.css" rel="stylesheet">Theme not switching
Ensure Mermaid is loaded before calling init():
// Wait for Mermaid to be available
await new Promise(resolve => setTimeout(resolve, 100));
await init();Export not working
The export feature requires modern browsers with Canvas API support. Check browser console for errors.
Support
Made with love for the Mermaid.js community
