PromptHub
Developer Tools Swift Development

Stop Embedding WebViews! BeautifulMermaid Renders Diagrams Natively in Swift

B

Bright Coding

Author

12 min read
31 views
Stop Embedding WebViews! BeautifulMermaid Renders Diagrams Natively in Swift

Stop Embedding WebViews! BeautifulMermaid Renders Diagrams Natively in Swift

What if I told you that every time you embed a WKWebView just to render a simple flowchart, you're sacrificing 60MB of memory, 200ms of startup latency, and your user's battery life? Here's the dirty secret Apple won't shout about: WebViews are the silent killers of native app performance. They're overkill for diagram rendering, yet thousands of Swift developers still cargo-cult them into their apps because "that's how it's always been done."

But what if there was a pure Swift solution that parses Mermaid syntax and renders gorgeous diagrams directly through Core Graphics? No JavaScript. No DOM. No memory-hogging web processes. Enter BeautifulMermaid — the native Swift port that's making WebView-based diagramming look like a relic from 2015.

Built by lukilabs and powered by the Eclipse Layout Kernel (ELK), BeautifulMermaid doesn't just match web-based renderers. In many cases, it surpasses them. Seventeen built-in themes. Six diagram types. Async rendering. SwiftUI integration. And yes — it even outputs ASCII art for your terminal-loving soul. Ready to burn your WebView bridges? Let's dive deep.

What is BeautifulMermaid?

BeautifulMermaid is a native Swift implementation of the popular beautiful-mermaid TypeScript library, meticulously ported to eliminate JavaScript dependencies entirely. It leverages elk-swift — a minimal Swift wrapper around the Eclipse Layout Kernel — to compute graph layouts with mathematical precision, then renders the results through Core Graphics for buttery-smooth performance.

The project emerged from a simple observation: Apple platforms deserve first-class diagram tooling. While Mermaid.js dominates the web ecosystem, bringing it to iOS, macOS, and visionOS traditionally meant swallowing a WebView whole. BeautifulMermaid rejects this compromise. It parses Mermaid syntax natively, computes layouts through proven algorithms, and outputs UIImage, NSImage, SVG, or even ASCII art — all without leaving the Swift runtime.

Why is it trending now? Three forces converged. First, Swift 5.9's improved concurrency made async rendering patterns elegant and safe. Second, visionOS's launch created demand for cross-platform rendering that WebViews struggle to optimize for spatial computing. Third, developer fatigue with WebView bloat reached a tipping point — BeautifulMermaid on GitHub solves this with surgical precision.

The library supports iOS 15+, macOS 12+, Mac Catalyst 15+, and visionOS 1.0+, making it immediately deployable across Apple's entire modern ecosystem. With MIT licensing and Swift Package Manager distribution, adoption friction approaches zero.

Key Features That Destroy the Competition

Six Diagram Types, Zero Compromise

BeautifulMermaid handles Flowcharts, State Diagrams, Sequence Diagrams, Class Diagrams, ER Diagrams, and XY Charts. Each parser is handcrafted in Swift, not transpiled from JavaScript, meaning error messages actually make sense and debugging doesn't require Chrome DevTools.

Multiple Output Formats for Every Context

Need a UIImage for a UICollectionViewCell? Done. SVG for PDF export? Easy. ASCII art for CLI tools or Slack messages? Surprisingly, yes. The MermaidRenderer class provides unified entry points, while specialized renderers like MermaidImageRenderer offer fine-grained control over PNG/JPEG export with configurable quality and scale.

Seventeen Built-in Themes + Infinite Customization

From Tokyo Night's electric blues to Gruvbox's retro warmth, themes aren't afterthoughts — they're first-class citizens. The DiagramTheme system derives complete color palettes from just two base colors through intelligent interpolation, or you can import any VS Code/Shiki theme for pixel-perfect editor consistency.

SwiftUI-First Architecture with UIKit/AppKit Fallbacks

The MermaidDiagramView is a proper SwiftUI View using value-type MermaidDiagram models. No @ObservableObject hacks, no UIViewRepresentable wrappers. For imperative UI code, MermaidView subclasses UIView/NSView directly, and MermaidLayer provides CALayer rendering for maximum compositional flexibility.

Async/Await for Modern Concurrency

Every render method has an Async variant. Diagram generation happens off the main thread without GCD boilerplate, integrating seamlessly with Swift's structured concurrency.

Pure Swift, Pure Performance

No WebView means no JavaScriptCore, no DOM, no layout thrashing. Memory footprint stays lean. Startup is instantaneous. Battery impact becomes negligible. On visionOS, this matters enormously — spatial apps can't afford WebView overhead.

Real-World Use Cases Where BeautifulMermaid Dominates

Technical Documentation Apps

Imagine a Markdown reader that renders Mermaid diagrams inline without the jarring WebView scroll performance. BeautifulMermaid's MermaidDiagramView integrates into ScrollView with native physics, supports Dynamic Type, and respects Reduced Motion settings automatically.

Developer Tools & IDEs

Build a Swift Playground alternative or Xcode extension that previews architecture diagrams. The ASCII art output enables terminal-based CI visualization — imagine your build pipeline printing sequence diagrams of service interactions directly in GitHub Actions logs.

Enterprise Dashboards

ER diagrams from live database schemas, flowcharts from workflow engines, state machines from IoT device telemetry — all rendered server-side or on-device without WebView sandboxing complications. The renderPNG method with scale: 3.0 generates print-ready assets for executive reports.

Education & Presentation Tools

Class diagram generation from Swift source code (via SourceKitten integration), animated sequence diagrams stepping through algorithm execution, or interactive XY charts for data science tutorials. The two-color theming system ensures accessibility compliance with minimal effort.

visionOS Spatial Experiences

WebViews in spatial computing are notoriously problematic — they're flat planes in a 3D world with awkward input handling. BeautifulMermaid's CALayer output textures directly onto RealityKit meshes, enabling floating diagram annotations in mixed reality.

Step-by-Step Installation & Setup Guide

Swift Package Manager Integration

Add BeautifulMermaid to your Package.swift dependencies:

// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "YourAwesomeApp",
    platforms: [.iOS(.v15), .macOS(.v12), .visionOS(.v1)],
    dependencies: [
        .package(url: "https://github.com/lukilabs/beautiful-mermaid-swift", from: "1.0.0")
    ],
    targets: [
        .target(
            name: "YourAwesomeApp",
            dependencies: [.product(name: "BeautifulMermaid", package: "beautiful-mermaid-swift")]
        )
    ]
)

For Xcode projects, use File → Add Package Dependencies and paste the repository URL. The SPM resolution automatically pulls elk-swift as a transitive dependency.

Minimal Configuration

No Info.plist entries. No entitlements. No App Transport Security exceptions. BeautifulMermaid is self-contained — the ELK layout engine ships as Swift source, not a binary framework, eliminating code signing headaches.

Project Structure Best Practices

Create a dedicated DiagramService actor for concurrent rendering:

import BeautifulMermaid

actor DiagramService {
    private let renderer = MermaidImageRenderer()
    
    func generateThumbnail(from mermaidCode: String) async throws -> UIImage {
        renderer.theme = .nord
        renderer.scale = 2.0
        return try await renderer.renderPNGAsync(from: mermaidCode)
    }
}

This isolates mutable renderer state while enabling parallel diagram generation across your app.

REAL Code Examples from the Repository

Basic Rendering: Image, SVG, and ASCII

The quintessential BeautifulMermaid workflow — parse once, render everywhere:

import BeautifulMermaid

let mermaidCode = """
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Do Something]
    B -->|No| D[Do Something Else]
    C --> E[End]
    D --> E
"""

// Native UIImage/NSImage — Core Graphics backed, no WebView
let image = try MermaidRenderer.renderImage(source: mermaidCode)

// Scalable Vector Graphics for print/export
let svg = try MermaidRenderer.renderSVG(source: mermaidCode, theme: .tokyoNight)

// Terminal-friendly ASCII art — surprisingly useful for CLI tools
let ascii = try MermaidRenderer.renderASCII(source: mermaidCode, theme: .zincDark)

What's happening here? MermaidRenderer is the high-level facade. It parses the Mermaid syntax into an abstract syntax tree, delegates layout to elk-swift, then renders through platform-appropriate graphics contexts. The theme: parameter injects color resolution at render time, not parse time — enabling identical diagrams with different palettes without re-layout.

SwiftUI Integration: Declarative Diagrams

import SwiftUI
import BeautifulMermaid

struct ContentView: View {
    var body: some View {
        // MermaidDiagramView is a native SwiftUI View — no UIViewRepresentable wrapper needed
        MermaidDiagramView(
            source: "graph TD; A-->B; B-->C;",
            theme: .catppuccinMocha  // Soothing pastel theme, trending in developer tools
        )
        .frame(height: 300)
        .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

Critical insight: MermaidDiagramView uses a value-type MermaidDiagram model. When the source string changes, SwiftUI's diffing efficiently triggers re-render without view identity destruction. This enables smooth animations when diagram content updates — impossible with WebView-based approaches that flash white during reloads.

UIKit/AppKit: Imperative Control

import BeautifulMermaid

// MermaidView is a true UIView/NSView subclass — not a wrapper
let mermaidView = MermaidView(frame: CGRect(x: 0, y: 0, width: 400, height: 300))
mermaidView.source = "graph TD; A-->B; B-->C;"
mermaidView.theme = .catppuccinMocha

// Direct subview addition — works in cells, headers, any view hierarchy
view.addSubview(mermaidView)

Why this matters: Because MermaidView inherits from UIView, it participates fully in Auto Layout, safe area insets, and trait collection changes. No manual frame synchronization. No KVO on scroll view content offsets. It just works like every other native view.

High-Resolution Export for Retina Displays

let renderer = MermaidImageRenderer()
renderer.theme = .dracula        // Classic dark theme with vibrant accents
renderer.scale = 3.0             // @3x for iPhone 15 Pro, Vision Pro displays

// PNG with alpha channel — perfect for overlaying on arbitrary backgrounds
let pngData = try renderer.renderPNG(from: mermaidCode)

// JPEG with quality control — smaller size for network transmission
let jpegData = try renderer.renderJPEG(from: mermaidCode, quality: 0.9)

Pro tip: The scale property multiplies the logical diagram dimensions. A 400×300 diagram at scale: 3.0 generates 1200×900 pixels. For visionOS, consider scale: 4.0 — spatial displays reveal every pixel.

Async Rendering for Responsive UIs

// All render methods have async variants using Swift's structured concurrency
let image = try await MermaidRenderer.renderImageAsync(source: mermaidCode, theme: .nord)
let svg = try await MermaidRenderer.renderSVGAsync(source: mermaidCode)
let ascii = try await MermaidRenderer.renderASCIIAsync(source: mermaidCode)

Concurrency safety: These methods run on cooperative thread pools, not the main thread. In SwiftUI, wrap calls in .task modifiers. In UIKit, use Task { ... } with @MainActor for UI updates. The parser and layout engine are re-entrant — safe for parallel diagram generation.

Custom Two-Color Theming

// Minimal theming: just background and foreground
// BeautifulMermaid automatically derives all other colors
let minimalTheme = DiagramTheme(
    background: "#1a1b26",  // Tokyo Night's deep navy
    foreground: "#c0caf5"   // Soft periwinkle text
)

// Enriched theming: full control over every semantic color
let detailedTheme = DiagramTheme(
    background: "#1a1b26",
    foreground: "#c0caf5",
    line: "#565f89",        // Subdued edge connections
    accent: "#7aa2f7",      // Highlighted decision nodes
    muted: "#414868",       // De-emphasized alternate paths
    surface: "#24283b",     // Elevated node backgrounds
    border: "#414868"       // Subtle node boundaries
)

The magic: Two-color themes use perceptual color space interpolation. Given background and foreground, BeautifulMermaid computes contrast ratios, derives semantic roles, and ensures WCAG 2.1 AA compliance automatically.

VS Code Theme Import

// Import your exact editor theme for documentation consistency
let shikiTheme = DiagramTheme.ShikiTheme(
    type: "dark",
    colors: [
        "editor.background": "#1e1e1e",
        "editor.foreground": "#d4d4d4",
        "focusBorder": "#007acc"
    ],
    tokenColors: []  // Optional: semantic token overrides
)

let theme = DiagramTheme.fromShikiTheme(shikiTheme)

Advanced Usage & Best Practices

Layout Tuning for Complex Diagrams

let config = LayoutConfig(
    padding: 20,              // Internal node padding
    nodeSpacing: 40,          // Horizontal gap between siblings
    layerSpacing: 60,         // Vertical gap between hierarchy levels
    componentSpacing: 40      // Gap between disconnected subgraphs
)

let renderer = MermaidImageRenderer()
renderer.layoutConfig = config

Tighten nodeSpacing for compact mobile layouts, or expand layerSpacing for presentation slides. The ELK engine respects these as soft constraints, gracefully handling edge cases.

Direction Control in Mermaid Syntax

graph TD    // Top-Down (default)
graph BT    // Bottom-Top — reverse dependency arrows
graph LR    // Left-Right — wide timelines
graph RL    // Right-Left — RTL language support

Performance Optimization

Cache MermaidDiagram value types for repeated renders with different themes. The expensive parse+layout phase happens once; re-rendering with new colors is near-instantaneous. For scrollable lists, use MermaidLayer directly — CALayer backing stores are GPU-friendly and don't trigger view hierarchy walks.

Error Handling Strategy

BeautifulMermaid throws descriptive MermaidError enums. Distinguish parseError (invalid syntax) from layoutError (ELK constraint failure) from renderError (Core Graphics context issues). Log syntax errors for user correction, but retry layout errors with relaxed LayoutConfig.

Comparison with Alternatives

Feature BeautifulMermaid WebView + Mermaid.js SwiftPlantUML Core Graphics Manual
WebView Required ❌ No ✅ Yes ❌ No ❌ No
JavaScript Runtime ❌ None ✅ JSEngine ❌ None ❌ None
Mermaid Syntax ✅ Native ✅ Full ❌ UML Only ❌ N/A
Output Formats Image, SVG, ASCII Image, SVG, PNG Image, SVG Image only
SwiftUI Native ✅ First-class ❌ Wrapper needed ❌ Wrapper ❌ Wrapper
Async Rendering ✅ Built-in ❌ Manual ❌ Manual ❌ Manual
Built-in Themes 17 + custom CSS-based Limited None
Memory Footprint ~5MB ~60MB+ ~10MB ~2MB
visionOS Support ✅ Optimized ⚠️ Problematic ❌ Unknown ✅ Possible
ASCII Art Output ✅ Yes ❌ No ❌ No ❌ No

The verdict: WebView solutions offer full Mermaid.js compatibility but at enormous runtime cost. SwiftPlantUML serves UML-specific use cases well but lacks Mermaid's breadth. Manual Core Graphics coding provides maximum control with maximum tedium. BeautifulMermaid occupies the sweet spot: native performance with declarative convenience.

Frequently Asked Questions

Does BeautifulMermaid support all Mermaid.js features?

No — and intentionally so. HTML in node labels, click callbacks, tooltips, FontAwesome icons, and style/linkStyle directives are currently unsupported. These require DOM capabilities that contradict the native rendering philosophy. Standard diagram syntax for flowcharts, state, sequence, class, ER, and XY charts works comprehensively.

Can I use this in a Widget or Live Activity?

Absolutely. BeautifulMermaid's pure Swift implementation has no background process requirements, making it ideal for WidgetKit's memory-constrained environments. Pre-render diagrams in your main app, cache PNG data, and display via Image(uiImage:) in widgets.

How do I handle diagram updates in SwiftUI?

The MermaidDiagramView automatically re-renders when its source binding changes. For complex state, derive a MermaidDiagram value type from your model and pass it directly — this enables precise SwiftUI diffing and animation support.

Is the ASCII art output actually useful?

Surprisingly yes. CI/CD logs, Slack/Discord code blocks, terminal-based documentation tools, and accessibility screen readers all benefit. The ASCII renderer uses box-drawing characters for crisp rendering in monospace contexts.

Can I contribute new diagram types or themes?

BeautifulMermaid is MIT-licensed and actively maintained. The parser architecture is modular — new diagram types implement the DiagramParser protocol. Themes require only color definition, with automatic derivation handling the complexity.

What about performance with 100+ node diagrams?

ELK's layered layout algorithm scales to thousands of nodes. For interactive scenarios, use renderImageAsync with a TaskPriority of .userInitiated to maintain UI responsiveness. Consider MermaidLayer for static backgrounds where view hierarchy overhead matters.

Does it work with Objective-C projects?

BeautifulMermaid uses Swift-only features (async/await, value types, generics) that aren't Objective-C compatible. Bridge through a Swift wrapper class annotated with @objc for mixed projects, or migrate diagram rendering to a Swift module.

Conclusion: The Native Future of Diagram Rendering

BeautifulMermaid isn't merely a WebView replacement — it's a fundamental reimagining of how diagram rendering should work on Apple platforms. By embracing Swift's type system, structured concurrency, and declarative UI frameworks, it delivers performance and integration impossible with JavaScript-based alternatives.

The seventeen built-in themes, two-color theming system, and VS Code theme import ensure visual consistency with your existing toolchain. The six supported diagram types cover the vast majority of technical visualization needs. And the ASCII art output? That's the kind of delightful surprise that separates good tools from great ones.

But here's what truly excites me: this is just the beginning. With visionOS adoption accelerating and Swift's ecosystem maturing, native rendering approaches like BeautifulMermaid will define the next generation of cross-platform development tools.

Stop accepting WebView mediocrity. Your users' batteries will thank you. Your scroll performance will thank you. Your future self, maintaining that codebase in 2027, will definitely thank you.

Star BeautifulMermaid on GitHub — and start rendering diagrams the way nature (and Apple) intended: natively, beautifully, purely in Swift.

Comments (0)

Comments are moderated before appearing.

No comments yet. Be the first to share your thoughts!

Support us! ☕