Layout, Styling, Themes, and Clickable Nodes
Take control of how diagrams look. Nudge layout and spacing with direction choices, subgraphs, and link length; apply color with classDef, the style directive, and per-diagram theme settings (including front-matter config and themeVariables). Then wire up interactivity — click a node to open a URL or jump to an anchor — which is where your own-site rendering really pays off.
Layout, Styling, Themes, and Clickable Nodes
Earlier submodules gave you working diagrams. This one makes them look intentional — and, on your own site, makes them interactive.
Nudging layout
Direction is the first lever. TD vs LR you already know. When different sections of the same diagram suit different orientations, individual subgraphs can declare their own:
flowchart TD
subgraph pipeline [CI Pipeline]
direction LR
A[Lint] --> B[Test] --> C[Build] --> D[Deploy]
end
subgraph review [Review Flow]
direction TB
E[PR Created] --> F{Approved?}
F -->|yes| G[Merged]
F -->|no| H[Changes Requested]
endEach subgraph renders internally in its own direction while the outer diagram stays TD. One documented limitation: if any node *inside* a subgraph has a direct edge to something *outside* it, the direction override is silently dropped. Route external edges to the subgraph ID — not to a node inside — to keep the override alive.
Link length nudges spacing between nodes. Each extra dash adds one rank of separation:
A --> B default gap
A ----> B wider
A -------> B wider stillThis works on dotted and thick edges too — -.-> becomes -..->. Reach for it when a long edge label overlaps a neighboring node, or when two nodes are visually cramped. If layout still looks off, try reordering node declarations in the source — the renderer places nodes in definition order before the algorithm runs.
flowchart TD
subgraph pipeline [CI Pipeline]
direction LR
P1[Lint] --> P2[Test] --> P3[Build] --> P4[Deploy]
end
subgraph review [Review Flow]
direction TB
R1[PR Created] --> R2{Approved?}
R2 -->|yes| R3[Merged]
R2 -->|no| R4[Changes Requested]
endclassDef: reusable node styles
classDef is the right tool for applying the same style to multiple nodes. Define a class once, assign it anywhere:
flowchart LR
classDef success fill:#22c55e,stroke:#16a34a,color:#fff
classDef error fill:#ef4444,stroke:#dc2626,color:#fff
classDef pending fill:#f59e0b,stroke:#d97706,color:#000
classDef default fill:#f1f5f9,stroke:#94a3b8,color:#1e293bApply with the ::: shorthand right on the node declaration — no separate statement needed:
B -->|valid| C[Process]:::success
B -->|invalid| D[Reject]:::error
C --> E[Queued]:::pendingOr assign in bulk: class nodeA,nodeB,nodeC myClass; on its own line. classDef default is a special name that sets the baseline for every node without an explicit class — define it first, then let named classes override it.
Properties that work inside classDef and style: fill, stroke, stroke-width, color (text color), font-weight, font-size, rx, ry (corner radius). One firm rule from the official docs: avoid styling Mermaid nodes via external CSS. Mermaid's internal styles have higher specificity, so external overrides rarely stick. Use classDef, style, and linkStyle exclusively.
flowchart LR
classDef success fill:#22c55e,stroke:#16a34a,color:#fff
classDef error fill:#ef4444,stroke:#dc2626,color:#fff
classDef pending fill:#f59e0b,stroke:#d97706,color:#000
classDef default fill:#f1f5f9,stroke:#94a3b8,color:#1e293b
A([Request]) --> B{Auth?}
B -->|valid| C[Handler]:::success
B -->|expired| D[Refresh]:::pending
B -->|invalid| E[Reject]:::error
C --> F[(Database)]:::success
D --> B
style A fill:#3b82f6,stroke:#2563eb,color:#fff
linkStyle 0 stroke:#3b82f6,stroke-width:2px
linkStyle 3 stroke:#ef4444,stroke-width:2pxstyle and linkStyle: targeted overrides
When a single node needs something that doesn't warrant a named class:
style E fill:#7c3aed,stroke:#6d28d9,color:#fff,stroke-dasharray: 5 5stroke-dasharray: 5 5 draws a dashed border — useful for flagging a "planned but not yet built" component. Accepts the same properties as classDef but applies only to the named node and can't be reused. If you catch yourself writing the same style on two or three nodes, that's the signal to make it a class.
Edges follow the same pattern. linkStyle targets edges by 0-based index in definition order:
flowchart LR
A --> B --> C
linkStyle 0 stroke:#ef4444,stroke-width:2px
linkStyle 1,2 stroke:#94a3b8,stroke-dasharray: 4 2Tracking indices in a complex diagram gets tedious fast, so save linkStyle for the edges that genuinely need visual priority — a critical path, an error branch, a fallback route.
Themes and per-diagram config
Five built-in themes: default, neutral, dark, forest, base. Pass one to mermaid.initialize({ theme: 'dark' }) on your site and every diagram inherits it globally.
For per-diagram control, put a YAML frontmatter block at the very top of the diagram source:
---
config:
theme: base
themeVariables:
primaryColor: '#1e3a5f'
primaryTextColor: '#ffffff'
primaryBorderColor: '#0f2d4f'
lineColor: '#64748b'
background: '#f8fafc'
---
flowchart TD
A[Client] --> B[API] --> C[(Database)]Two rules that catch most people:
1. Only base is customizable. The other four themes have fixed palettes; themeVariables on them is silently ignored. Always pair theme: base with your variable overrides.
2. Hex colors only. Named colors like cornflowerblue and rgb() values are both silently ignored. Use #6495ed.
primaryColor drives the default node fill. primaryBorderColor auto-adjusts when you change primaryColor, but can be overridden explicitly. For sequence diagrams the key variables are actorBkg and noteBkgColor; for state diagrams, stateBkg. The full list lives in the Mermaid theming docs.
You may encounter %%{init: {"theme": "base"} }%% at the top of diagrams online — that's the old directive syntax, now deprecated. It still parses in most renderers, but when writing new diagrams, use the frontmatter block above.
Click directives: wiring nodes to URLs
Hosted renderers like GitHub disable clicks for security. On your own site you control the initialization — that's what makes this worthwhile.
Step 1 — set securityLevel when initializing Mermaid:
mermaid.initialize({
securityLevel: 'loose',
});Step 2 — add click statements at the bottom of the diagram:
flowchart LR
classDef linked fill:#2563eb,stroke:#1d4ed8,color:#fff
A[Home] --> B[API Docs] --> C[Reference]
click A "https://example.com" "Homepage" _blank
click B "https://example.com/api" "API reference" _blank
click C href "https://example.com/ref" _self
class A,B,C linkedSyntax: click nodeId "url" "optional tooltip" target. Targets: _blank (new tab), _self (current tab — the default). The href keyword between node ID and URL is optional. For on-page anchors, a relative fragment works fine: click B "#authentication" scrolls to the matching heading on the same page — a clean pattern for documentation sites where one long page embeds multiple diagrams.
Two gotchas that waste time:
- If
securityLevelis'strict'(Mermaid's default), click directives are silently dropped. The diagram renders normally; clicks just do nothing, with no error or warning. Setting'loose'is always the fix. - Click directives don't fire in the mermaid.live Live Editor. Test on an actual local HTML page, not the preview pane.
flowchart LR
classDef linked fill:#2563eb,stroke:#1d4ed8,color:#fff
A[Home] --> B[Docs] --> C[Reference]
A --> D[Examples]
click A "https://example.com" "Homepage" _blank
click B "https://example.com/docs" "Read the docs" _blank
click C "https://example.com/ref" "Full reference" _self
click D "#examples" "Jump to examples"
class A,B,C,D linkedKeeping styled diagrams maintainable
A few habits that scale:
- Lock down your palette with
classDef. Three or four consistent class names —success,error,warning,info— used across all diagrams in a doc make the whole site feel coherent without extra effort. classDef defaultas the baseline. Define it first in every diagram; let named classes override it.- Keep
styleandlinkStyleto genuine outliers. If the same override appears on three nodes, it belongs in a class. - Test click directives on a local page early. Wire up one node, confirm it fires, then add the rest.
Quick check
1. Write a flowchart LR with three classDef classes — distinct hex colors — and at least four nodes styled with :::.
2. Add a classDef default to set the baseline for un-styled nodes.
3. Write a YAML frontmatter block with theme: base and a primaryColor override. Paste it into mermaid.live to confirm it renders.
4. Add two click directives — one _blank, one with a #fragment anchor. Set up a minimal local HTML page with securityLevel: 'loose' and confirm both fire.
The final submodule covers keeping large diagrams readable and embedding them on your own site — including when to reach for mermaid.run() versus letting Mermaid auto-initialize.
Self-check
- You want node C (outside a subgraph) to connect to node A (inside a subgraph with `direction LR`). You write `C --> A`. What happens?
- Your diagram has a long edge label that overlaps an adjacent node. You add extra dashes to the edge. What does this actually do?
- You're styling three error nodes and one special critical node with a dashed border. Which approach is best?
- You set `theme: dark` with custom `themeVariables` in YAML frontmatter. The custom colors don't appear. What's wrong?
- You wrote `click A 'https://example.com'` and tested it on mermaid.live without success. Your local page has `securityLevel: 'strict'`. Changing it to `'loose'` makes it work. Why?
- You want two clickable nodes: one opening a new tab to an external site, another scrolling to a page heading. Which syntax is correct?
- You find an old diagram with `%%{init: {"theme": "dark"} }%%` at the top. What should you know about this?
- You style Mermaid nodes with an external CSS rule but the colors don't apply. Why?
Homework
Design and style a workflow diagramtext
Build a Mermaid flowchart for a deployment pipeline or support ticket workflow. You'll need at least three `classDef` classes—each with its own hex color—to style different node types. Apply them to at least 6 nodes using `:::`. Include a subgraph that overrides direction (so maybe that section flows left-to-right while everything else goes top-to-bottom). Use extended link syntax (----> instead of -->) once or twice to add spacing. Always define `classDef default` first—it's your baseline for unstyled nodes. Test on mermaid.live to make sure it renders, then submit the complete source code.
• Defines 3+ classDef classes with distinct hex colors • Applies classes to at least 6 nodes using ::: syntax • Includes at least one subgraph with direction override • Uses extended link syntax (4+ dashes) at least once • classDef default is defined first, before other classes • Diagram renders without errors on mermaid.live • Source code is complete and ready to run
Apply theme customization and embed in HTMLarchive
Take your diagram from Assignment 1 and add custom theming. Put a YAML frontmatter block at the very top (--- on its own line, config inside, --- again). Set `theme: base` and include at least two `themeVariables` with hex colors. Remember: only `base` respects theme variables; other themes ignore them. Create an HTML file with Mermaid loaded and your diagram in a `<pre class="mermaid">` block. Open it in a browser, verify your custom colors appear, then submit the HTML file in a .zip.
• YAML frontmatter is syntactically correct (--- delimiters, proper YAML) • Uses `theme: base` (not other built-in themes) • Includes 2+ themeVariables with hex color values • All color values use hex format (#rrggbb) • Diagram is in a <pre class="mermaid"> block • HTML initializes Mermaid with mermaid.initialize() and mermaid.run() • Custom colors are visibly applied when file opens in browser • Archive contains a working, self-contained HTML file
Create an interactive navigation diagramarchive
Build a diagram for a site navigation, feature roadmap, or component map. Add at least 4 click directives: at least 2 pointing to external URLs with target="_blank", and at least 2 pointing to page anchors like #faq or #getting-started. Critical detail: your HTML must initialize Mermaid with `securityLevel: 'loose'`—without it, clicks silently don't work. Add matching anchor points to your HTML (e.g., `<h2 id="faq">FAQ</h2>`) so fragment clicks navigate. Test locally to confirm clicks fire, and leave an HTML comment documenting what you tested. Submit as a .zip.
• HTML initializes Mermaid with `securityLevel: 'loose'` • Diagram contains 4+ click directives • At least 2 click directives use external URLs with target="_blank" • At least 2 click directives use fragment anchors (e.g., #section-name) • HTML includes id attributes matching at least 50% of fragment links • All click statements are syntactically correct • Clicks are tested and functional when file opens locally • File is valid HTML and opens without errors • Archive contains a working, self-contained HTML file
Submit and get assignments reviewed in the Learn (Almost) Anything app.
