# External Libraries (CDN) Optional CDN libraries for cases where pure CSS/HTML isn't enough. Only include what the diagram actually needs — most diagrams need zero external JS. ## Mermaid.js — Diagramming Engine Use for flowcharts, sequence diagrams, ER diagrams, state machines, mind maps, class diagrams, and any diagram where automatic node positioning and edge routing saves effort. Mermaid handles layout — you handle theming. Do NOT use for dashboards — CSS Grid card layouts with Chart.js look better for those. Data tables use `` elements. **CDN:** ```html ``` **With ELK layout** (required for `layout: 'elk'` — it's a separate package, not bundled in core): ```html ``` Without the ELK import and registration, `layout: 'elk'` silently falls back to dagre. Only import ELK when you actually need it — it adds significant bundle weight. Most simple diagrams render fine with dagre. ### Deep Theming Always use `theme: 'base'` — it's the only theme where all `themeVariables` are fully customizable. The built-in themes (`default`, `dark`, `forest`, `neutral`) ignore most variable overrides. ```html ``` **FORBIDDEN in Mermaid themeVariables:** `#8b5cf6`, `#7c3aed`, `#a78bfa` (indigo/violet), `#d946ef` (fuchsia). Use teal, slate, amber, emerald, or colors from your page's palette. ### CSS Overrides on Mermaid SVG Mermaid renders SVG. Override its classes for pixel-perfect control that `themeVariables` can't reach: ```css /* Container — see html-css-patterns.md "Mermaid Zoom Controls" for the full zoom pattern */ .mermaid-wrap { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 24px; overflow: auto; } /* CRITICAL: Force node/edge text to follow the page's color scheme. Without this, themeVariables.primaryTextColor works for DEFAULT nodes, but any classDef that sets color: will hardcode a single value that breaks in the opposite color scheme. Fix: never set color: in classDef, and always include these CSS overrides. */ .mermaid .nodeLabel { color: var(--text) !important; } .mermaid .edgeLabel { color: var(--text-dim) !important; background-color: var(--bg) !important; } .mermaid .edgeLabel rect { fill: var(--bg) !important; } /* Node shapes */ .mermaid .node rect, .mermaid .node circle, .mermaid .node polygon { stroke-width: 1.5px; } /* Edge paths */ .mermaid .edge-pattern-solid { stroke-width: 1.5px; } /* Edge labels — smaller than node labels for visual hierarchy */ .mermaid .edgeLabel { font-family: var(--font-mono) !important; font-size: 13px !important; } /* Node labels — 16px default; drop to 14px for complex diagrams (20+ nodes) */ .mermaid .nodeLabel { font-family: var(--font-body) !important; font-size: 16px !important; } /* Sequence diagram actors */ .mermaid .actor { stroke-width: 1.5px; } /* Sequence diagram messages */ .mermaid .messageText { font-family: var(--font-mono) !important; font-size: 12px !important; } /* ER diagram entities */ .mermaid .er.entityBox { stroke-width: 1.5px; } /* Mind map nodes */ .mermaid .mindmap-node rect { stroke-width: 1.5px; } ``` ### classDef and style Gotchas `classDef` values and per-node `style` directives are static text inside `
` — they can't use CSS variables or JS ternaries. Two rules:

1. **Never set `color:` in classDef or per-node `style` directives.** It hardcodes a text color that breaks in the opposite color scheme. Let the CSS overrides above handle text color via `var(--text)`.

2. **Use semi-transparent fills (8-digit hex) for node backgrounds.** They layer over whatever Mermaid's base theme background is, producing a tint that works in both light and dark modes. Use `20`–`44` alpha for subtle, `55`–`77` for prominent:

```
classDef highlight fill:#b5761433,stroke:#b57614,stroke-width:2px
classDef muted fill:#7c6f6411,stroke:#7c6f6444,stroke-width:1px
```

### Node Label Special Characters

Mermaid uses certain characters for shape syntax. Node labels containing these characters cause syntax errors unless quoted.

**Shape characters to watch:**
- `[/text/]` — parallelogram
- `[(text)]` — cylindrical
- `[[text]]` — subroutine
- `((text))` — circle
- `{{text}}` — hexagon

**If your node label starts with `/`, `\`, `(`, or `{`, wrap it in quotes:**

```
%% WRONG — syntax error (/ starts parallelogram shape)
CMD[/gallery command] --> SRV[server]

%% RIGHT — quotes escape the special character
CMD["/gallery command"] --> SRV[server]
```

**Edge labels with special characters also need quotes:**

```
%% WRONG
UI -->|"Use as Reference"| RET

%% RIGHT — use single quotes or no quotes for simple text
UI -->|Use as Reference| RET
```

Avoid opaque light fills like `fill:#fefce8` — they render as bright boxes in dark mode.

### stateDiagram-v2 Label Limitations

State diagram transition labels have a strict parser. Avoid:
- `
` — only works in flowcharts; causes a parse error in state diagrams - Parentheses in labels — `cancel()` can confuse the parser - Multiple colons — the first `:` is the label delimiter; extra colons may break parsing If you need multi-line labels or special characters, use a `flowchart` instead of `stateDiagram-v2`. Flowcharts support quoted labels (`|"label with: special chars"|`) and `
` for line breaks. ### Writing Valid Mermaid Most Mermaid failures come from a few recurring issues. **For multi-line flowchart node labels, use `
` (not `\n`):** ``` %% WRONG — renders literal "\n" in node text A["Copilot Backend\n/api + /api/voicebot"] --> B["Redis"] %% RIGHT — renders on two lines A["Copilot Backend
/api + /api/voicebot"] --> B["Redis"] ``` **Quote labels with special characters.** Parentheses, colons, commas, brackets, and ampersands break the parser when unquoted: ``` A["handleRequest(ctx)"] --> B["DB: query users"] A[handleRequest] --> B[query users] ``` **Keep IDs simple.** Node IDs should be alphanumeric with no spaces or punctuation: ``` userSvc["User Service"] --> authSvc["Auth Service"] ``` **Max 10-12 nodes per Mermaid diagram.** Beyond that, readability collapses even with zoom controls. For complex architectures (15+ elements), use the **hybrid pattern**: a simple 5-8 node Mermaid overview showing module relationships, followed by CSS Grid cards with detailed function lists. ``` subgraph Auth login --> validate --> token end subgraph API gateway --> router --> handler end Auth --> API ``` **Arrow styles for semantic meaning:** | Arrow | Meaning | Use for | |-------|---------|---------| | `-->` | Solid | Primary flow | | `-.->` | Dotted | Optional, async, or fallback paths | | `==>` | Thick | Critical or highlighted path | | `--x` | Cross | Rejected or blocked | | `-->\|label\|` | Labeled | Decision branches, data descriptions | **Sequence diagram messages must be plain text.** Unlike flowchart labels, sequence diagram messages cannot be quoted or escaped. Curly braces `{}`, square brackets `[]`, angle brackets `<>`, and `&` will silently break the parser: ``` %% WRONG — parser chokes on braces, brackets, ampersand A->>B: web_search({ queries: [...] }) B->>B: User removes query 2, keeps 1 & 3 %% RIGHT — plain English, no special characters A->>B: Call web_search with queries B->>B: User removes query 2, keeps 1 and 3 ``` ### Layout Direction: TD vs LR `flowchart LR` (left-to-right) spreads horizontally. With many nodes, Mermaid scales everything down to fit the width, making text unreadable. `flowchart TD` (top-down) is almost always better. | Direction | Use when | Avoid when | |-----------|----------|------------| | `TD` (top-down) | Complex diagrams, 5+ nodes, hierarchies | Simple A→B→C linear flows | | `LR` (left-to-right) | Simple linear flows, 3-4 nodes | Complex graphs, many branches | **Rule of thumb:** If the diagram has more than one row of nodes or any branching, use `TD`. ### Diagram Type Examples **Flowchart with decisions:** ```html
graph TD
  A[Request] --> B{Authenticated?}
  B -->|Yes| C[Load Dashboard]
  B -->|No| D[Login Page]
  D --> E[Submit Credentials]
  E --> B
  C --> F{Role?}
  F -->|Admin| G[Admin Panel]
  F -->|User| H[User Dashboard]
``` **Sequence diagram:** ```html
sequenceDiagram
  participant C as Client
  participant G as Gateway
  participant S as Service
  participant D as Database
  C->>G: POST /api/data
  G->>G: Validate JWT
  G->>S: Forward request
  S->>D: Query
  D-->>S: Results
  S-->>G: Response
  G-->>C: 200 OK
``` **ER diagram:** ```html
erDiagram
  USERS ||--o{ ORDERS : places
  ORDERS ||--|{ LINE_ITEMS : contains
  LINE_ITEMS }o--|| PRODUCTS : references
  USERS { string email PK }
  ORDERS { int id PK }
  LINE_ITEMS { int quantity }
  PRODUCTS { string name }
``` **State diagram:** ```html
stateDiagram-v2
  [*] --> Draft
  Draft --> Review : submit
  Review --> Approved : approve
  Review --> Draft : request_changes
  Approved --> Published : publish
  Published --> Archived : archive
  Archived --> [*]
``` **Mind map:** ```html
mindmap
  root((Project))
    Frontend
      React
      Next.js
      Tailwind
    Backend
      Node.js
      PostgreSQL
      Redis
    Infrastructure
      AWS
      Docker
      Terraform
``` **Class diagram:** ```html
classDiagram
  class User {
    +string email
    +string name
    +login()
    +logout()
  }
  class Order {
    +int id
    +decimal total
    +submit()
  }
  class Product {
    +string name
    +decimal price
  }
  User "1" --> "*" Order : places
  Order "*" --> "*" Product : contains
``` **C4 architecture (flowchart-as-C4):** ```html
graph TD
  user("User
Browser client") subgraph boundary["Web Platform"] app["Web App
Node.js"] db[("Database
PostgreSQL")] end email["Email Service"]:::ext payment["Payment Gateway"]:::ext user -->|"HTTPS"| app app -->|"SQL"| db app -->|"SMTP"| email app -->|"API"| payment classDef ext fill:none,stroke-dasharray:5 5
``` Do NOT use native `C4Context` / `C4Container` syntax — it hardcodes sharp corners, its own font, and inline colors that ignore `themeVariables`. Use `graph TD` + `subgraph` for C4 boundaries instead. ### Which Mermaid Diagram Type? | You want to show... | Use | Syntax keyword | |---|---|---| | Process flow, decisions, pipelines | Flowchart | `graph TD` / `graph LR` | | Request/response, API calls, temporal interactions | Sequence diagram | `sequenceDiagram` | | Database tables and relationships | ER diagram | `erDiagram` | | OOP classes, domain models with methods | Class diagram | `classDiagram` | | System architecture at multiple zoom levels | C4 diagram | `graph TD` + `subgraph` | | State transitions, lifecycles | State diagram | `stateDiagram-v2` | | Hierarchical breakdowns, brainstorms | Mind map | `mindmap` | ### Dark Mode Handling Mermaid initializes once — it can't reactively switch themes. Read the preference at load time inside your ` ``` Wrap the canvas in a styled container: ```css .chart-container { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 20px; position: relative; } .chart-container canvas { max-height: 300px; } ``` --- ## anime.js — Orchestrated Animations Use when a diagram has 10+ elements and you want a choreographed entrance sequence (staggered reveals, path drawing, count-up numbers). For simpler diagrams, CSS `animation-delay` staggering is sufficient. ```html ``` When using anime.js, set initial opacity to 0 in CSS so elements don't flash before the animation: ```css .ve-card { opacity: 0; } @media (prefers-reduced-motion: reduce) { .ve-card { opacity: 1 !important; } } ``` --- ## Google Fonts — Typography Always load with `display=swap` for fast rendering. Pick a distinctive pairing — body + mono at minimum, optionally a display font for the title. **FORBIDDEN as `--font-body` (AI slop signals):** - Inter — the single most overused AI default font - Roboto — generic Android/Google default - Arial, Helvetica — system defaults with no character - system-ui alone without a named font — signals zero design intent ```html ``` Define as CSS variables for easy reference: ```css :root { --font-body: 'Outfit', system-ui, sans-serif; --font-mono: 'Space Mono', 'SF Mono', Consolas, monospace; } ``` **Font pairings** (rotate — never use the same pairing twice in a row): | Body / Headings | Mono / Labels | Feel | Use for | |---|---|---|---| | DM Sans | Fira Code | Friendly, developer | Blueprint, technical docs | | Instrument Serif | JetBrains Mono | Editorial, refined | Plan reviews, decision logs | | IBM Plex Sans | IBM Plex Mono | Reliable, readable | Architecture diagrams | | Bricolage Grotesque | Fragment Mono | Bold, characterful | Data tables, dashboards | | Plus Jakarta Sans | Azeret Mono | Rounded, approachable | Status reports, audits | | Outfit | Space Mono | Clean geometric, modern | Flowcharts, pipelines | | Sora | IBM Plex Mono | Technical, precise | ER diagrams, schemas | | Crimson Pro | Noto Sans Mono | Scholarly, serious | RFC reviews, specs | | Fraunces | Source Code Pro | Warm, distinctive | Project recaps | | Geist | Geist Mono | Vercel-inspired, sharp | Modern API docs | | Red Hat Display | Red Hat Mono | Cohesive family | System overviews | | Libre Franklin | Inconsolata | Classic, reliable | Data-dense tables | | Playfair Display | Roboto Mono | Elegant contrast | Executive summaries | The first 5 pairings are recommended for most use cases. Vary across consecutive diagrams. ### Typography by Content Voice For prose-heavy pages (documentation, articles, essays), match typography to the content's voice: | Voice | Fonts | Best For | |-------|-------|----------| | **Literary / Thoughtful** | Literata, Lora, Newsreader, Merriweather | Essays, personal posts, long-form articles | | **Technical / Precise** | IBM Plex Sans + Mono, Geist + Geist Mono, Source family | Documentation, READMEs, API references | | **Bold / Contemporary** | Bricolage Grotesque, Space Grotesk, DM Sans | Product pages, feature announcements | | **Minimal / Focused** | Source Serif 4 + Source Sans 3, Karla + Inconsolata | Tutorials, how-tos, focused reading | **Literata** deserves special mention — it has optical sizing designed specifically for screen reading. Google's answer to Georgia, but modernized.