Files
Ashish Jain efe218a47f Release candidate 11.14.0 (#7526)
* fix(wardley): Handle dual-label evolution stages and evolve syntax

1. Fix evolution stage parsing to combine name + secondName (e.g., "Genesis / Concept")
2. Fix Evolve rule to accept ID/NAME_WITH_SPACES, not just STRING
3. Fix NAME_WITH_SPACES regex to not match digits after spaces
   - Now matches "Campfire Kettle" but stops at "Kettle" in "Kettle 0.5"
   - Pattern: /[A-Za-z][A-Za-z0-9_()&]*(?:\s+[A-Za-z][A-Za-z0-9_()&]*)*/

This fixes:
- "parses dual-label evolution stages with slashes" test
- "parses evolve statements" test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Prevent NAME_WITH_SPACES from matching newlines

Changed \s+ to [ \t]+ in NAME_WITH_SPACES regex to only match spaces
and tabs, not newlines. This prevents the terminal from consuming line
breaks and causing "Expecting NEWLINE or EOF" errors.

Fixes:
- "parses custom evolution stages" test
- "parses dual-label evolution stages with slashes" test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Fix pipeline parent name and bidirectional flow

1. Pipeline rule now accepts ID/NAME_WITH_SPACES for parent, not just STRING
   - Allows `pipeline Kettle {` without quotes
2. Reorder LINK_PORT alternatives to match longest first (+<> before +< and +>)
   - Fixes bidirectional flow detection (was matching +< instead of +<>)

Fixes:
- "parses pipeline blocks with single-coordinate components" test
- "handles quoted identifiers, inline labels, and converts coordinates to percentages" test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Support negative label offsets and optional arrow in links

1. Label rule now accepts INT with optional minus sign for negative offsets
   - Changed from WARDLEY_NUMBER to INT with negX/negY flags
   - Handle negative values in wardleyParser.ts
2. Link arrow is now optional when LINK_PORT is present
   - Allows syntax like `"Mobile App" +<> API` without explicit arrow

Fixes:
- "parses pipeline blocks with single-coordinate components" test
- "handles quoted identifiers, inline labels, and converts coordinates to percentages" test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Allow parentheses after spaces in component names

Fixed NAME_WITH_SPACES terminal regex to allow parentheses, digits, and
underscores after spaces. This enables component names like "byte pair
encoding (BPE)" to parse correctly.

Previously, the pattern required letters after spaces which rejected
component names with parentheses like "(BPE)" after spaces.

Changed pattern from:
  (?:[ \t]+[A-Za-z][A-Za-z0-9_()&]*)*
To:
  (?:[ \t]+[A-Za-z0-9_()&]+)*

Fixes E2E test "should render GPT Tokeniser Architecture"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Allow integer coordinates in annotations

Extended WARDLEY_NUMBER terminal to match both decimals (0.5) and
integers (1, 100) to support annotations syntax like [1, 0].

The previous regex /[0-9]+\.[0-9]+/ only matched decimals, causing
parsing errors for integer coordinates in the annotations statement.

Changed to: /[0-9]+\.[0-9]+|[0-9]+/

Fixes GPT Tokeniser test which uses `annotations [1, 0]`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore(wardley): Remove dead code from valueConverter

Removed unused case handlers for terminals that no longer exist in the
grammar (COMPONENT_NAME, EVOLUTION_NAME, TEXT_UNTIL_BRACKET, TEXT_LINE).
These were remnants from earlier grammar iterations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(wardley): Improve coordinate validation error message

Clarified the error message for invalid coordinates to explain that
values can be either 0-1 (decimal, converted to percentage) or 0-100
(percentage, used as-is).

Before: "must be between 0 and 1 (0-100)"
After:  "must be between 0-1 (decimal) or 0-100 (percentage)"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(wardley): Make area dimensions configurable

Added `areaWidth` and `areaHeight` configuration options to allow users
to customize the size of area rectangles in Wardley diagrams.

New config options:
- `areaWidth`: Width of area rectangles in pixels (default: 120)
- `areaHeight`: Height of area rectangles in pixels (default: 80)

Example usage:
```
%%{init: {'wardley-beta': {'areaWidth': 150, 'areaHeight': 100}}}%%
wardley-beta
area "My Area" [0.5, 0.5]
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(wardley): Remove area feature (not in OWM spec)

Removed the `area` feature as it is not part of the standard Online
Wardley Maps (OWM) specification. This keeps the implementation aligned
with the official OWM syntax.

Removed:
- `area` grammar rule and KW_AREA terminal
- Area parsing, building, and rendering code
- WardleyArea interface and related types
- areaWidth/areaHeight config options
- Area test case
- Area documentation section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: pie: Don't sort, keep order.  Keep color order constant.

* Adds Tachi Code to browser extensions list

* sample of what I want to see change

* add show data label outside bar but don't do anything with it yet

* progress commit

return unchanged arrow function to inline

look at extreme cases

reduce duplication and improve naming

[autofix.ci] apply automated fixes

improve example cases to highlight incongruity

some hacks for easier debugging

wip of removing font width requirement for horizontal out of bar stuff

remove some prior experimentation we don't need anymore

simplified horizontal handling

much simpler methodology seems to work across different examples

* add cypress tests

* add documentation

* fixes to cypress test

* fix line removed by accident

* docs format and content fixes

* add release version label to markdown heading within docs

* add changeset

* fix: align branch label background with text for multi-line labels in LR GitGraph

The background rectangle for branch labels was misaligned with the text
when branch names contained multi-line text (e.g. "Feature A\n(ongoing)")
in LR layout. The old transform used `pos - bbox.height / 2` which caused
the rect to shift further up as text height increased, while the text
position remained centered at `pos - 1`.

Fixed by using a constant y-offset (`pos - 11`) in the transform,
derived from the constraint that the rect center must equal the text
center regardless of bbox.height.

Closes #7362

* fix typo introduced when addressing merge conflicts

* fix more typos introduced while addressing merge conflict

* fix demo index

* change order of docs in nav bar so new diagram is at the bottom

* add an example

* use example from issue to improve examples

* make treeview demo page consistent with treemap demo page (it's fancier)

* add changeset

* fix examples failing test

* add failing parser tests for treeview

* wip understanding parser

* parser WIP

* fix naming conflict

* handle null case

* add indent tests

* adjust indent test (affected by whitespace handling?)

* indent tests behave differently locally to pipeline. comment out to check review branch

* possible option is to return indent length instead of actual indent (speculative since indent works locally, but not in pipeline)

* Revert "possible option is to return indent length instead of actual indent (speculative since indent works locally, but not in pipeline)"

This reverts commit b85199f38a.

* test

* Revert "Revert "possible option is to return indent length instead of actual indent (speculative since indent works locally, but not in pipeline)""

This reverts commit 209d2623b5.

* try this again in pipeline

* this reordering made a difference locally

* issue with treeview accessibility test is because of fragility with whitespace in front of content that should not have leading whitespace. is it just the test that is fragile?

* update docs to include link to langium docs and playground

* fix: make treemap title and labels theme-aware for dark background readability

* restore comment ignoring, and comment

* fix: scope node/edge element IDs to diagram SVG to prevent duplicates

When multiple mermaid diagrams appear on the same page, internal SVG
element IDs for nodes and edges collide (e.g., flowchart-A-0 appears
twice). This causes invalid HTML (WCAG 4.1.1), broken url(#...) refs,
and CSS selectors matching the wrong element.

Prefix all internal element IDs with the diagram's SVG element ID
(e.g., mermaid-0-flowchart-A-0), following the same pattern used for
marker IDs in PR #4825.

Changes:
- render.ts: prefix all node domIds before layout
- edges.js: prefix edge path IDs with diagram ID
- createGraph.ts: prefix edge label node IDs
- flowDb.ts/classDb.ts: add setDiagramId(), defer click handler
  domId lookup to bind time so prefixed IDs are used
- flowRenderer/classRenderer: call setDiagramId() before getData()
- flowRenderer: fix link selector to use domId instead of id

Affects all diagram types that go through the unified render path:
flowchart, class, state, ER, requirement, mindmap.

https://claude.ai/code/session_01FPVnyf54nFQNQnhZ7dSWCE

* chore: add node-compile-cache to .gitignore

https://claude.ai/code/session_01FPVnyf54nFQNQnhZ7dSWCE

* test: trim unique DOM ID tests from 355 to 161 lines

Extract addFlowVertex helper to deduplicate verbose addVertex calls.
Remove three describe blocks that only tested local mock functions
(string concatenation), keeping all tests that exercise real FlowDB/ClassDB
code and the full collision simulation.

https://claude.ai/code/session_01FPVnyf54nFQNQnhZ7dSWCE

* refactor: clean up diagramId code per review feedback

- Rename setDiagramId param from `id` to `svgElementId` for clarity
- Add setDiagramId to DiagramDB interface to centralize the contract
- Remove stale "defer lookUpDomId" comments in classDb.ts
- Remove PR #4825 reference from render.ts comment

https://claude.ai/code/session_01FPVnyf54nFQNQnhZ7dSWCE

* refactor: centralize diagramId field and setter into ScopedDiagramDB base class

Extract shared `diagramId` field and `setDiagramId` setter from FlowDB
and ClassDB into a new abstract base class `ScopedDiagramDB`. Both DB
classes now extend it instead of duplicating the field and method.

https://claude.ai/code/session_01FPVnyf54nFQNQnhZ7dSWCE

* Revert "refactor: centralize diagramId field and setter into ScopedDiagramDB base class"

This reverts commit 7245574ab2.

* fix: ensure unique SVG element IDs across multiple mermaid diagrams

Fix unscoped element IDs in clusters.js (5 locations), defaultMindmapNode.ts,
and kanbanRenderer.ts that caused duplicate DOM IDs when multiple diagrams
with identical node names appeared on the same page.

Add self-enforcing integration test that renders two identical diagrams for
every registered diagram type and asserts no duplicate element IDs. The test
auto-detects new diagram types via the registry and fails if they're not
covered. Legacy renderers with known issues use it.fails to document them.

Add runtime duplicate-ID warning in mermaid.run() (debug log level only)
with a pre-filled GitHub issue link for easy reporting.

Add Cypress tests for browser-level multi-diagram ID uniqueness verification.

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* chore: add generated .d.ts files from examples package build

These type declaration files are generated by the prepare script during
pnpm install. Adding them to avoid untracked file warnings.

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* Revert "chore: add generated .d.ts files from examples package build"

This reverts commit 10002cf8d1.

* chore: gitignore generated .d.ts files from examples package

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* simplify: drop runtime warning and test over-engineering

New diagram types are added ~once per 5 months. The 4-category test
taxonomy (unified/simple/legacy/jsdom-incompatible), self-enforcement
registry check, and runtime duplicate-ID warning were not worth the
maintenance cost. Simplified to a flat list of diagram tests that
covers all types where IDs should be unique.

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* refactor: drop domId fallback in clusters.js, extract Cypress helper

Remove `|| node.id` fallback from clusters.js — every code path that
calls insertCluster (dagre, cose-bilkent, kanban) already sets domId.
The fallback silently hid missing domId bugs instead of surfacing them.

Extract assertNoDuplicateIds into cypress/helpers/util.ts and use it
in both marker_unique_id and multi_diagram_unique_ids specs.

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* fix: namespace marker/element IDs with diagram ID to prevent collisions

Prefix all hardcoded SVG marker IDs (arrowhead, filled-head, crosshead,
sequencenumber, etc.) and element IDs with the diagram's unique ID in
sequence, journey, timeline, gantt, and C4 renderers. This prevents
cross-diagram ID collisions when multiple diagrams render on the same page.

Covers: sequence (12 markers), journey (arrowhead), timeline (arrowhead),
C4 (arrowhead, arrowend, filled-head, crosshead, sequencenumber, plus
database/computer/clock symbols), and gantt (task + exclude-day IDs).

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* test: add sequence, journey, timeline, gantt, C4 to multi-diagram ID uniqueness tests

Extends the parametrized renderTwoAndCheckIds test suite to cover all 5
diagram types that previously had hardcoded marker/element IDs. Also fixes
a pre-existing bug in timeline's svgDraw.js where node IDs were
`node-undefined` (now uses a monotonic counter prefixed with diagram ID).

All 19 diagram types now pass the duplicate-ID stress test.

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* test: add meta-test enforcing ID uniqueness coverage for all diagram types

Adds a meta-test that cross-references the detector registry against the
test map, so any new diagram type added to mermaid will fail CI unless it
has a corresponding ID uniqueness test (or is explicitly excluded with a
justification).

Also documents block and architecture as known-failing (pre-existing ID
collision bugs tracked via it.fails), and excludes mindmap (cytoscape
JSDOM limitation, uses unified pipeline so IDs are correct).

https://claude.ai/code/session_01QCm1SAitm8ZpLjjsk7eFv3

* test: add comprehensive stress tests for multi-diagram ID uniqueness

Exercises the ID scoping mechanism under adversarial conditions:
- 5x identical diagrams for 10 different diagram types (flowchart, class,
  ER, state, sequence, gantt, pie, C4, journey, timeline)
- Complex graphs with 20 nodes and fan-out topologies
- Nested subgraphs (3 levels deep)
- Mixed diagram types on the same page (up to 10 types simultaneously)
- FlowDB/ClassDB unit-level stress with 10-100 instances
- Sequential render stability and clear/reset cycles
- Adversarial node names that mimic diagramId prefixes
- SVG marker definition uniqueness (sequence, C4)
- Edge label ID uniqueness across renders
- Kanban, git graph, requirement, XY chart, quadrant, sankey
- Diagram ID prefix propagation verification

https://claude.ai/code/session_01MtKnkbaUyKZY6R5vTrMNam

* fix: scope journey task line IDs with diagramId to prevent collisions

The journey diagram's svgDraw.js used bare `task0`, `task1`, etc. as
element IDs without any diagram-scoped prefix. This worked by accident
because the module-level taskCount never reset, but was fragile and
inconsistent with the ID scoping pattern used by all other diagram types.

Fix:
- Store the diagramId passed to initGraphics()
- Reset taskCount on each render via initGraphics()
- Prefix task line IDs with diagramId (e.g. `mermaid-0-task0`)

https://claude.ai/code/session_01MtKnkbaUyKZY6R5vTrMNam

* test: add targeted journey task-line ID test, remove stress tests

Add a focused regression test that verifies journey diagram task line
IDs are scoped with the diagramId prefix. This test fails against the
pre-fix code (bare "task0"/"task1" IDs) and passes after the fix
("journey-a-task0"/"journey-b-task0").

Remove the large stress test file — the targeted test plus the existing
multi-diagram-id-uniqueness suite provide sufficient coverage.

https://claude.ai/code/session_01MtKnkbaUyKZY6R5vTrMNam

* refactor: trim journey task-line ID test by reusing renderTwoAndCheckIds

https://claude.ai/code/session_01MtKnkbaUyKZY6R5vTrMNam

* test: add comprehensive stress tests for multi-diagram ID uniqueness

Add 43 stress tests covering scenarios beyond the basic two-diagram tests:
- Scale: 10 and 20 identical diagrams of 11 different types (flowchart,
  class, sequence, journey, timeline, gantt, C4, state, ER, pie, git)
- Cross-type: mixed diagram types rendered into a single container
- Subgraphs/clusters: nested and multi-level subgraph ID isolation
- Large diagrams: 50-node flowcharts, 20-message sequences, 20-class
  diagrams, 15-task journeys
- Minimal diagrams: single-node/single-message edge cases
- DiagramId boundaries: hyphenated, underscored, numeric-prefixed IDs
- Sequential re-rendering: clear-and-rerender and append-without-clear
- Module-level counter resets: journey taskCount and timeline nodeCount
- SVG marker/defs scoping: sequence, flowchart, and C4 markers
- DB-layer scoping: FlowDB and ClassDB lookUpDomId under 5x stress
- Kanban pre-flight domId injection
- Gantt special characters in task IDs

All 43 tests pass, confirming the ID uniqueness fix holds under stress.

https://claude.ai/code/session_012gG2dXNE8BJAZfHJjs96aX

* fix: resolve three ID-scoping issues found during stress testing

1. flowDb.ts lookUpDomId fallback: when called with an ID not in the
   vertex map (e.g. subgraph IDs), the fallback now applies the
   diagramId prefix instead of returning the bare ID.

2. sequence/svgDraw.js drawActorTypeControl: remove the `|| ''`
   fallback on conf.diagramId that produced colliding marker IDs
   (e.g. "-filled-head-control") when multiple sequence diagrams
   share a page. The renderer always sets conf.diagramId before
   rendering, so the fallback was masking a potential collision.

3. Eliminate module-level diagramId variables in sequence, journey,
   and timeline renderers to prevent race conditions in concurrent
   or SSR rendering scenarios:
   - sequenceRenderer.ts: use conf.diagramId instead of redundant
     module-level diagramId variable
   - journey/svgDraw.js: pass diagramId as parameter to drawTask
     instead of reading from module scope
   - timeline/svgDraw.js: pass diagramId as parameter to drawTask,
     drawNode, and defaultBkg; also fixes timeline drawTask which
     was missing the diagramId prefix entirely ("task0" vs
     "diagramId-task0")
   - timeline/timelineRenderer.ts: pass diagramId through drawTasks
     and drawEvents instead of reading from module-level
     currentDiagramId

Adds 5 regression tests that would have failed before these fixes.

https://claude.ai/code/session_012gG2dXNE8BJAZfHJjs96aX

* fix: remove diagramId ternary fallbacks — always prefix

lookUpDomId in flowDb and classDb, and createGraph's edge-label
domId, all had `diagramId ? prefixed : bare` ternaries. Since the
render pipeline always calls setDiagramId before any lookups, the
bare-ID fallback just silently masked missing diagramId bugs. Now
these always prefix, making a missing setDiagramId call surface
immediately.

https://claude.ai/code/session_012gG2dXNE8BJAZfHJjs96aX

* chore: added pnpm changeset

* [autofix.ci] apply automated fixes

* fix: replace dead/wrong domId fallbacks with loud failures

The `|| node.id` / `|| vertex.id` / `: edge.id` fallbacks are dead
code — render.ts always sets domId before shape/edge functions run.
Worse, if reached, they'd silently produce unscoped IDs, reintroducing
the duplicate-ID bug this PR fixes.

Changes:
- defaultMindmapNode.ts: throw on missing domId, use node.domId directly
- flowRenderer-v3-unified.ts: throw on missing domId, use vertex.domId
- edges.js: rename `id` param to `diagramId`, throw if missing, drop
  ternary fallback to bare edge.id

* fix: use diagramId instead of undefined id in insertEdge edge markers

The addEdgeMarkers call on line 777 referenced `id` which was never
defined in insertEdge's scope — the parameter is named `diagramId`.
This caused:
- ESLint no-undef lint failure
- ReferenceError at runtime in all diagrams using the unified renderer
- All unit tests and e2e tests to fail

Also adds unit tests for the three defensive throw guards introduced
in the PR (insertEdge, flowRenderer, defaultMindmapNode) to achieve
100% coverage on new code.

https://claude.ai/code/session_01JzR5nomkuYcHxMJ67FMuW4

* fix: resolve E2E test failures caused by ID-prefixed SVG elements

The PR's ID-prefixing changes caused three categories of E2E failures:

1. Double <a> wrapping in flowRenderer: The link-wrapping loop (lines
   68-105) was dead code before the PR because vertex.id never matched
   the rendered element's actual ID. The PR's switch to vertex.domId
   activated this dead code, creating a second <a> inside .node that
   broke cy.contains().find('.node') in Cypress. Fix: remove the
   redundant loop since nodes.ts (lines 36-51) already wraps link
   nodes in <svg:a> during rendering, including sandbox support
   (target="_top"). The removed sandboxElement and doc variables were
   only used by this redundant loop and had no other consumers in the
   function — sandbox mode is fully preserved via nodes.ts.

2. Edge animation selectors: path#L_A_B_0 no longer matches because
   edge IDs are now prefixed with diagramId. Fix: use attribute
   selectors path[id$="-L_A_B_0"].

3. Gantt/rerender selectors: rect#cl1, text#cl1-text, and
   [id^=flowchart-A] no longer match prefixed IDs. Fix: use
   [id$="-cl1"], [id$="-cl1-text"], and [id*=flowchart-A].

https://claude.ai/code/session_012TZWtntRQbGFN6Sk9qDuhE

* fix: prefix gantt task IDs in click handlers to match rendered element IDs

The gantt click handler (pushFun in ganttDb.js) used document.querySelector
with the raw task ID (e.g., "cl2"), but the renderer now sets element IDs
as "${diagramId}-${taskId}" (e.g., "mermaid-0-cl2"). This meant click
event listeners were never attached, breaking all gantt click interactions
(both URL navigation and function callbacks) in the E2E tests.

Fix: Add setDiagramId to ganttDb.js (matching the pattern used by
flowDb.ts and classDb.ts), call it from the gantt renderer's draw
function, and use the prefixed ID in pushFun's querySelector calls.

https://claude.ai/code/session_012TZWtntRQbGFN6Sk9qDuhE

* fix: update CSS ID selectors to match prefixed SVG element IDs

The PR prefixes all SVG marker IDs with the diagram container ID
(e.g., `mermaid-0-arrowhead` instead of `arrowhead`), but the CSS
styles.js files still used hardcoded `#arrowhead`, `#crosshead`, etc.
selectors that no longer matched. This caused markers/arrowheads to
lose their themed fill/stroke colors, producing subtle visual diffs
detected by Argos CI.

Replace all `#id` selectors with `[id$="-suffix"]` attribute selectors
that match the new prefixed IDs:

- sequence/styles.js: #arrowhead, #sequencenumber, #crosshead
- class/styles.js: #compositionStart/End, #dependencyStart/End,
  #extensionStart/End, #aggregationStart/End, #lollipopStart/End
- state/styles.js: #statediagram-barbEnd, #dependencyStart/End

Also fixes a pre-existing bug in class/styles.js where #dependencyStart
was duplicated instead of having #dependencyEnd.

https://claude.ai/code/session_01DP7eBkBQuMUqZRkvJBdmyS

* fix: give ER background nodes a unique domId to prevent duplicate IDs

The erBox shape creates background nodes by spreading the parent node
and overriding `id` with a '-background' suffix, but the spread also
copies `domId`. Since the SVG element uses `domId || id`, both the
foreground and background nodes ended up with the same DOM ID. This
caused the background-positioning logic in erRenderer-unified.ts to
fail (it selects by `[id*="-background"]`), leaving background nodes
un-positioned and visible as duplicate tables.

https://claude.ai/code/session_01KzNAdiCYp8tZZoBogdbhin

* refactor: drop unnecessary domId fallback in erBox background node

render.ts always sets node.domId before erBox runs, so the
`|| node.id` fallback is dead code.

https://claude.ai/code/session_01KzNAdiCYp8tZZoBogdbhin

* refactor: drop unnecessary domId fallback in erBox shape element

Same rationale as the background node — render.ts guarantees domId
is set before shape rendering.

https://claude.ai/code/session_01KzNAdiCYp8tZZoBogdbhin

* fix: use nullish coalescing fallback for domId in erBox shape

domId is optional on the Node type since it's not yet assigned during
getData(). Use ?? node.id as a defensive fallback, matching the
convention used by every other shape renderer in the codebase.

https://claude.ai/code/session_01UXvz61L5VFDwLmWDqbhfxm

* fix: address code review feedback on duplicate SVG element IDs

- Guard lookUpDomId() against empty diagramId in flowDb.ts and classDb.ts
  to prevent malformed IDs like "-flowchart-A-0" when diagramId is unset
- Pass diagramId as a parameter to drawMessage() in sequenceRenderer.ts
  instead of mutating the shared conf object
- Update changeset to accurately list covered diagram types and note
  that remaining types will be addressed in follow-up PRs

https://claude.ai/code/session_01UDSa3mTe2uhLiTYVn7cXQg

* fix: restore conf.diagramId for svgDraw.js and fix test comments

Red-team found that svgDraw.js drawActorTypeControl() reads
conf.diagramId directly (lines 690, 712), so removing the mutation
would break control actor marker rendering. Keep conf.diagramId
assignment for svgDraw.js compatibility while also passing diagramId
as a clean parameter to drawMessage().

Also fix misleading test comments that said "prefix is just '-'" —
with the empty diagramId guard, no prefix is applied at all.

https://claude.ai/code/session_01UDSa3mTe2uhLiTYVn7cXQg

* refactor: thread diagramId as parameter instead of mutating conf

Remove conf.diagramId mutation entirely. Pass diagramId explicitly
through draw() → drawActors() → drawActor() → drawActorTypeControl()
so svgDraw.js no longer reads diagramId from the shared config object.

https://claude.ai/code/session_01UDSa3mTe2uhLiTYVn7cXQg

* fix: update changeset to minor and reflect full diagram coverage

All diagram types are effectively covered by the unique DOM ID prefixing,
not just a subset. Bump from patch to minor since this is a behavioral
change to generated IDs.

https://claude.ai/code/session_01UDSa3mTe2uhLiTYVn7cXQg

* fix: add ishikawa/venn to ID uniqueness tests and fix architecture test timeout

After merging develop, two new diagram types (ishikawa, venn) were added
upstream but missing from the multi-diagram ID uniqueness test map,
causing the meta-test to fail. The architecture svgDraw test also timed
out under parallel execution due to CPU-intensive cytoscape layout.

- Add ishikawa and venn entries to DIAGRAMS map in
  multi-diagram-id-uniqueness.spec.ts
- Increase architecture svgDraw describe timeout to 15s to handle
  resource contention during full test suite runs

https://claude.ai/code/session_0195arHUvMWxqnYF8JxcWPru

* refactor(types): correct types for `createText.ts`

Fix the TypeScript types for `createText.ts`, allowing us to remove the
`@ts-nocheck` statement. I've also made sure to get rid of all the `any`
types in this file.

* docs: add a TSDoc comment to `createText()`

* fix: support classDef styling inside composite states

* fix(architecture): scope cytoscape label mapping to edges with labels

The edge stylesheet selector applied `label: 'data(label)'` to all
edges, including those without titles. This caused cytoscape to emit
console warnings about mapping data to elements without corresponding
data fields. Split the edge selector so label mapping only applies via
`edge[label]`, matching the existing `node[label]` guard pattern.

Resolves #6031

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add small TSDoc comment to decodeEntities()

I'm not exactly sure why `decodeEntities()` is needed and what it does,
but I added a brief comment to make it a bit more clear that it's
**NOT** decoding HTML entities, but just decoding what `encodeEntities`
is doing.

* refactor: `decodeEntities` if `htmlLabels: false`

In the `createText()` function, we are calling `decodeEntities()` on the
input if `htmlLabels: true`, but we weren't doing it `htmlLabels: false`
was set.

I can't seem to find anywhere this is actually impacting diagrams, since
we're calling `decodeEntities()` already normally before calling
`createText()`, hence why this is just a `refactor` commit.

Original-commit: https://github.com/mermaid-js/mermaid/pull/7297
Co-authored-by: chandershekhar22 <chandersj.it.22@nitj.ac.in>

* fix: prevent escaping `<` and `&` when `htmlLabels: false`

When creating labels using `htmlLabels: false`, e.g.

```mermaid
---
config:
    htmlLabels: false
---
flowchart TD
    A[2 < 4 && 12 > 14]
```

The SVG node label gets rendered as
`2 &lt; 4 &amp;&amp; 12 &gt; 14`. This is fine for HTML text, where we
use `.innerHTML` to set the value. But for non-HTML Labels, we use
`.textContent`, so we need to pass the unescaped values.

Ideally we would stop calling DOMPurify on this label when
`.textContent` is used, since the content doesn't need to be sanitized,
but adding a quick `&lt;`/`&gt;`/`&amp;`-> `<`/`>`/`&` also works.

I've adapted this commit from https://github.com/mermaid-js/mermaid/pull/6406.

Closes: https://github.com/mermaid-js/mermaid/pull/6406
Co-authored-by: khalil <5alil.landolsi@gmail.com>

* refactor: handle `node.padding==undefined`

TypeScript wasn't catching these earlier, since `bbox` was `any`,
but now that it's been typed correctly, all the `node.padding` uses in
expressions with `bbox` are throwing TypeScript errors.

* refactor(types): assert `.textContent` is non-null

According to MDN, this is only `null` if the `Node` is a `Document`.
I'm not 100% sure why TypeScript is throwing an error on this, since my
VS Code shows that `Element.textContent` will never be `null`, since
`Document` can never be an `Element`, but we do have other non-null
assertions for this scattered over the place.

See: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent

* refactor(types): type known `<div>` elements

We know that the output of `createText` when `htmlLabels: true` is set
is a `<foreignObject>` that contains a `<div>`, so this can fix our
TypeScript errors.

* fix(sequence): add catch-all rule for ID lexer state to prevent hang

The sequence diagram JISON parser had no catch-all rule in the exclusive
ID lexer state. When input like `participant X asAlias:text` was parsed
(missing space after "as"), none of the ID-state rules could match due
to the colon terminating the character class match before end-of-line.
This caused a lexer error that could hang browsers depending on error
recovery behavior.

Add a catch-all `<ID>[^\n]+` rule that produces an INVALID token when
no other ID-state rule matches, ensuring the parser always makes
progress and produces a clean parse error.

Resolves #6399

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: fix duplicate `createText` test case

See: https://github.com/mermaid-js/mermaid/pull/7436#pullrequestreview-3876840611

* refactor: remove unused requirement box unescaping

Replacing `&lt;` and `&gt;` in requirement shapes is no longer
necessary, now that `createText` does it automatically when `htmlLabels:
false`.

* fix(flowchart): warn when style targets a non-existent node

Resolves #7040

When a `style` statement references a node that hasn't been defined
(e.g., `style A fill:#f00` when only `AA` exists), log a warning
instead of silently creating a phantom node. The node is still created
for backward compatibility, but the warning helps users catch typos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(classDiagram): remove broken inline annotation example

Resolves #7143

The docs TIP blockquote recommended `class Shape <<interface>>` as
"inline" annotation syntax, but this is not valid — the parser grammar
has no rule for annotations after classIdentifier. Only the separate
line (`<<interface>> Shape`) and nested (`{ <<interface>> }`) syntaxes
are supported.

Removed the misleading TIP section. Added tests verifying both valid
annotation syntaxes match the remaining docs examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(gantt): document valid duration token formats

Resolves #7212

Added a "Duration format" section to gantt.md listing valid unit
suffixes (ms, s, h, d, w, M, y) with examples. Also notes that decimal
values are supported and invalid tokens are silently ignored.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use `<<` for requirement edge labels

Before
aac86f7de (fix: edge label rendering for ER and requirement diagrams when flowchart: { htmlLabels: false }, 2026-01-06),
we used to use `<<` for requirement edge labels.

However, due to a bug in `createText` with `useHtmlLabels: false`,
where `<` was being rendered as `&lt;`, we updated it to `«`.

Now that this bug has been fixed in
57b70b3ac (fix: prevent escaping `<` and `&` when `htmlLabels: false`, 2026-03-02),
we can revert this change and go back to using `<<`.

We have to encode it as `&lt;&lt;` instead of `<<`, as otherwise
`marked` treats it as HTML.

No changelog should be necessary, assuming this gets merged before the
next release.

* Add vertical timeline

* [autofix.ci] apply automated fixes

* add release version

* [autofix.ci] apply automated fixes

* add visual regression test

* handle string fontSize correctly

* Update gitignore

* Update gitignore

* chore(dev-deps): upgrade pnpm to v10.30.3

See: https://github.com/pnpm/pnpm/releases/tag/v10.30.3

* build: set a 3 day `minimumReleaseAge` for NPM

Set a 3 day `minimumReleaseAge` dependency cooldown for NPN dependencies,
so that we never automatically upgrade to a dependency that is less than
3 days old.

This helps avoid supply-chain attacks and prevents issues with NPM
packages being unpublished.

If we do need to manually update something, we can use
`minimumReleaseAgeExclude` for this.

See: https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
See: https://docs.renovatebot.com/presets-security/#securityminimumreleaseagenpm
See: https://pnpm.io/settings#minimumreleaseage

* ci(renovate): add dependency cooldown for CI/Docker

@renovatebot supports these for Docker images hosted on docker.io, and
most GitHub tags, but only for the `major`, `minor`, and `patch`
updates.

Digest updates usually won't work.

See: https://docs.renovatebot.com/key-concepts/minimum-release-age/#which-registries-support-release-timestamps
See: https://docs.renovatebot.com/key-concepts/minimum-release-age/#which-update-types-take-minimumreleaseage-into-account
See: https://github.com/renovatebot/renovate/discussions/39781#discussioncomment-15160296

* fix(classDiagram): support inline annotation syntax (class Shape <<interface>>)

Add grammar rules to classStatement for inline annotations instead of
removing the docs example. Supports three forms:
- class Shape <<interface>>
- class Shape <<interface>> { members }
- class Shape <<interface>> {}

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fix wording nit and rename changeset file

- "either way" → "in all cases" for three annotation methods
- Rename changeset to match fix approach

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Version Packages

* issue 1331 - draw children under same g

* fix: add E2E snapshot test and changeset for state diagram root <g> grouping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update .gitignore to include architecture-randomize.html in demos/dev

* feat(architecture): enable architecture diagram tests and add randomization demo

- Re-enabled tests for architecture diagrams, ensuring deterministic layouts.
- Added a new test for complex deeply-nested diagrams.
- Introduced a new HTML demo for testing architecture randomization configurations.

* feat(architecture): add `randomize` option for architecture diagrams layout

- Introduced a new `randomize` configuration option to allow random initial node positions in architecture diagrams.
- Updated the configuration schema and types to include the new option, defaulting to `false` for deterministic layouts.
- Modified the architecture renderer to utilize the `randomize` setting during layout calculations.

* refactor(architecture): standardize syntax in architecture diagram tests

- Updated the syntax for connections and labels in architecture diagram tests for consistency.
- Added a new test case to validate rendering with the `randomize` option set to true, ensuring no errors occur during the process.

* update parser to require spaces around content

* fix formatting

* generate new changeset (minor)

* support customising text colour and line colour separately - still need to check docs and e2e for this, but not theming

* update cypress

* reviewing other examples, it seems more consistent to refer to label than text eg labelFontSize and labelColor

* fix missed examples

* regenerate changeset

* make custom formatting examples more exaggerated to convey meaning more clearly

* new changeset

* add link to ishikawa diagram

* remove redundant change sets

* add theme support for data label colour in xy chart

* update changeset as per feedback

* use feat prefix in changeset

* fix: address PR review issues for duplicate SVG element IDs

- Restore .gitignore entries lost during merge conflict resolution
- Fix block diagram duplicate IDs by adding diagramId support to blockDB
  and prefixing node domIds and edge IDs in renderHelpers
- Fix architecture diagram duplicate IDs by adding diagramId to
  ArchitectureDB and prefixing all element IDs in svgDraw
- Move block/architecture from known-failing to passing tests
- Reset timeline taskCount in initGraphics to prevent counter leaks
- Add diagramId to LayoutData TypeScript interface for type safety
- Remove dead insertDynamicNumber function from C4 svgDraw
- Remove redundant `const diagramId = id` alias in sequence renderer
- Standardize domId fallback from ?? to || in erBox.ts

https://claude.ai/code/session_01SPyLYoNghEHAXG6a5Vtr2X

* fix: update architecture svgDraw test selectors for prefixed IDs

The test used un-prefixed selectors like `#group-api` and `[id^=service-]`
which no longer match after IDs are prefixed with the diagram's SVG element ID.

https://claude.ai/code/session_01SPyLYoNghEHAXG6a5Vtr2X

* docs: regenerate LayoutData docs for diagramId property

https://claude.ai/code/session_01SPyLYoNghEHAXG6a5Vtr2X

* Add IntelliJ Idea integration with Mermaid Visualizer

* [autofix.ci] apply automated fixes

* turn on data labels for Render all the theme color e2e test

* fix pnpm lock file

* merge v11.13.0 to develop

* fix: ER diagram parsing for numeric entity identifier "1"

The lexer now correctly tokenizes "1" followed by whitespace and a digit
as the ONLY_ONE cardinality token. This fixes parsing errors when using
"1" as an entity name on the right side of a relationship with cardinality 1.

Fixes #7472

* fix: prevent long pie chart titles from being clipped

When a pie chart has a long title (e.g. "Weekly Grocery Consumption for
a Family of 4"), the title text was clipped on the left side because the
SVG viewBox did not account for the title width.

The title is centered at x = pieWidth/2 in SVG coordinates. If the title
is wider than pieWidth, it extends past x=0 and gets clipped since the
viewBox started at x=0.

Fixed by measuring the rendered title width and expanding the viewBox
to accommodate it when the title is wider than the chart + legend area.

Closes #5567

* rework: use viewBox expansion for wide titles instead of group shifting

Replace the group-shift approach with direct viewBox expansion using
Math.min(0, titleLeft) / Math.max(chartAndLegendWidth, titleRight).
This correctly handles all overflow cases (left, right, or both)
without needing conditional group transforms.

Also rename legendWidth to chartAndLegendWidth for clarity.

* fix(ishikawa): preserve cause hierarchy when effect is indented more than causes

Set baseLevel from the first cause instead of the effect line, so
relative indentation between causes is preserved regardless of effect
indentation. Previously, all causes were clamped to level 1 when the
effect had higher indentation, destroying the parent-child hierarchy.

Resolves #7469

* test(ishikawa): add e2e visual test for indented effect with dedented causes

Adds snapshot test covering the scenario from #7469 where the effect
line is indented more than its causes.

* test: add boundary test for multi-digit numeric entity identifier

Add test case using entity "12" to ensure lexer fix covers
all numeric identifiers, not just single digit 1.

Refs #7472

* fix(treemap): add changeset and dark theme Cypress snapshot tests

Add a patch changeset for the theme-aware color fix.
Add Cypress snapshot tests verifying treemap readability on dark
and neutral themes.

Resolves #7218

* docs(gantt): add missing minutes (m) unit to duration format table

The parseDuration regex in ganttDb.js already supports 'm' for minutes,
and ganttDb.spec.ts has an existing test for it. Add the missing row.

* add spec

* chore: update mermaid version to minor for architecture diagram changes

* docs(architecture): add configuration section for `randomize` option in architecture diagrams

- Introduced a new section in the architecture documentation detailing the `randomize` option for initial node positions.
- Provided examples for enabling randomization via frontmatter and `mermaid.initialize()`.
- Updated the configuration table to include the new option and its default behavior.

* feat(schema): add `randomize` option to configuration schema

* fix typo in renovate config

* fix naming conflict

* regenerate lockfile

* add unit test for multi diagram id uniqueness

* chore: remove accidental planning/guide files from PR

Remove files that were accidentally committed and flagged by reviewers:
- PR_READY.md
- PR_SUBMISSION_GUIDE.md
- WARDLEY_MAPS_USER_GUIDE.md
- WARDLEY_MAPS_MEDIUM_GUIDE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* renovate config typo take 2

* oops I brought back the first typo

* fix: preserve original arrow types when splitting labeled edges

When an edge with a label gets split into two sub-edges (edge-to-label
and edge-from-label) in createGraph.ts, the arrow types were being
hardcoded instead of preserving the original edge's arrow types. This
caused labeled open edges (using --- syntax) to incorrectly show
arrowheads, and bidirectional labeled edges to lose their start arrows.

Now edgeToLabel preserves the original arrowTypeStart and edgeFromLabel
preserves the original arrowTypeEnd, fixing the rendering for all
labeled edge types.

Fixes #6289

* refactor: remove dead createGraphWithElements function, keep regression test

The createGraphWithElements function in createGraph.ts was exported but
never imported anywhere in the codebase. The original fix modified this
dead code path, which had no runtime effect.

The active code path in flowDb.ts already correctly handles arrow_open
edges by setting arrowTypeStart/End to 'none'. No edge splitting occurs
for labeled edges in the dagre layout — labels are rendered as floating
SVG elements positioned at the edge midpoint.

Removed the entire dead code file and kept the Cypress regression test
for open edge arrowhead behavior.

* Merge pull request #7501 from mermaid-js/feature/neo-look-base

feature: implement neo look and themes for mermaid diagrams

* fix: apply classDef styles correctly to divider element

on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>

* fix: iupdate branch label positioning

on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>

---------

Co-authored-by: tractorjuice <129532814+tractorjuice@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Danny Milosavljevic <gitea@fake.local>
Co-authored-by: David Septimus <davidseptimus@gmail.com>
Co-authored-by: leentaylor <leentaylor@gmail.com>
Co-authored-by: Lee Taylor <84303927+lee-treehouse@users.noreply.github.com>
Co-authored-by: Varun Chawla <varun_6april@hotmail.com>
Co-authored-by: Adam <adam@mymac.local>
Co-authored-by: Varun Chawla <34209028+veeceey@users.noreply.github.com>
Co-authored-by: Alex Turner <alex@turntrout.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Alois Klink <alois@aloisklink.com>
Co-authored-by: Knut Sveidqvist <knsv@users.noreply.github.com>
Co-authored-by: kibanana <kyw017763@gmail.com>
Co-authored-by: Knut Sveidqvist <knsv@sveido.com>
Co-authored-by: chandershekhar22 <chandersj.it.22@nitj.ac.in>
Co-authored-by: khalil <5alil.landolsi@gmail.com>
Co-authored-by: TATSUNO “Taz” Yasuhiro <ytatsuno.jp@gmail.com>
Co-authored-by: Sidharth Vinod <sidharthv96@gmail.com>
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dripcoding <dripcoding@gmail.com>
Co-authored-by: knsv-bot <knsv-bot@macos.shared>
Co-authored-by: Jeroen Smink <jeroensmink98@gmail.com>
Co-authored-by: Alex9583 <37045839+Alex9583@users.noreply.github.com>
Co-authored-by: GhassenS <ghassensiala12@gmail.com>
Co-authored-by: omkarht <omkar@mermaidchart.com>
Co-authored-by: darshanr0107 <darshan@mermaidchart.com>
2026-04-01 10:43:10 +02:00

30 KiB
Raw Permalink Blame History

Warning

THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.

Please edit the corresponding file in /packages/mermaid/src/docs/syntax/gantt.md.

Gantt diagrams

A Gantt chart is a type of bar chart, first developed by Karol Adamiecki in 1896, and independently by Henry Gantt in the 1910s, that illustrates a project schedule and the amount of time it would take for any one project to finish. Gantt charts illustrate number of days between the start and finish dates of the terminal elements and summary elements of a project.

A note to users

Gantt Charts will record each scheduled task as one continuous bar that extends from the left to the right. The x axis represents time and the y records the different tasks and the order in which they are to be completed.

It is important to remember that when a date, day, or collection of dates specific to a task are "excluded", the Gantt Chart will accommodate those changes by extending an equal number of days, towards the right, not by creating a gap inside the task. As shown here

However, if the excluded dates are between two tasks that are set to start consecutively, the excluded dates will be skipped graphically and left blank, and the following task will begin after the end of the excluded dates. As shown here

A Gantt chart is useful for tracking the amount of time it would take before a project is finished, but it can also be used to graphically represent "non-working days", with a few tweaks.

Mermaid can render Gantt diagrams as SVG, PNG or a MarkDown link that can be pasted into docs.

gantt
    title A Gantt Diagram
    dateFormat YYYY-MM-DD
    section Section
        A task          :a1, 2014-01-01, 30d
        Another task    :after a1, 20d
    section Another
        Task in Another :2014-01-12, 12d
        another task    :24d
gantt
    title A Gantt Diagram
    dateFormat YYYY-MM-DD
    section Section
        A task          :a1, 2014-01-01, 30d
        Another task    :after a1, 20d
    section Another
        Task in Another :2014-01-12, 12d
        another task    :24d

Syntax

gantt
    dateFormat  YYYY-MM-DD
    title       Adding GANTT diagram functionality to mermaid
    excludes    weekends
    %% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)

    section A section
    Completed task            :done,    des1, 2014-01-06,2014-01-08
    Active task               :active,  des2, 2014-01-09, 3d
    Future task               :         des3, after des2, 5d
    Future task2              :         des4, after des3, 5d

    section Critical tasks
    Completed task in the critical line :crit, done, 2014-01-06,24h
    Implement parser and jison          :crit, done, after des1, 2d
    Create tests for parser             :crit, active, 3d
    Future task in critical line        :crit, 5d
    Create tests for renderer           :2d
    Add to mermaid                      :until isadded
    Functionality added                 :milestone, isadded, 2014-01-25, 0d

    section Documentation
    Describe gantt syntax               :active, a1, after des1, 3d
    Add gantt diagram to demo page      :after a1  , 20h
    Add another diagram to demo page    :doc1, after a1  , 48h

    section Last section
    Describe gantt syntax               :after doc1, 3d
    Add gantt diagram to demo page      :20h
    Add another diagram to demo page    :48h
gantt
    dateFormat  YYYY-MM-DD
    title       Adding GANTT diagram functionality to mermaid
    excludes    weekends
    %% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)

    section A section
    Completed task            :done,    des1, 2014-01-06,2014-01-08
    Active task               :active,  des2, 2014-01-09, 3d
    Future task               :         des3, after des2, 5d
    Future task2              :         des4, after des3, 5d

    section Critical tasks
    Completed task in the critical line :crit, done, 2014-01-06,24h
    Implement parser and jison          :crit, done, after des1, 2d
    Create tests for parser             :crit, active, 3d
    Future task in critical line        :crit, 5d
    Create tests for renderer           :2d
    Add to mermaid                      :until isadded
    Functionality added                 :milestone, isadded, 2014-01-25, 0d

    section Documentation
    Describe gantt syntax               :active, a1, after des1, 3d
    Add gantt diagram to demo page      :after a1  , 20h
    Add another diagram to demo page    :doc1, after a1  , 48h

    section Last section
    Describe gantt syntax               :after doc1, 3d
    Add gantt diagram to demo page      :20h
    Add another diagram to demo page    :48h

Tasks are by default sequential. A task start date defaults to the end date of the preceding task.

A colon, :, separates the task title from its metadata. Metadata items are separated by a comma, ,. Valid tags are active, done, crit, and milestone. Tags are optional, but if used, they must be specified first. After processing the tags, the remaining metadata items are interpreted as follows:

  1. If a single item is specified, it determines when the task ends. It can either be a specific date/time or a duration. If a duration is specified, it is added to the start date of the task to determine the end date of the task, taking into account any exclusions.
  2. If two items are specified, the last item is interpreted as in the previous case. The first item can either specify an explicit start date/time (in the format specified by dateFormat) or reference another task using after <otherTaskID> [[otherTaskID2 [otherTaskID3]]...]. In the latter case, the start date of the task will be set according to the latest end date of any referenced task.
  3. If three items are specified, the last two will be interpreted as in the previous case. The first item will denote the ID of the task, which can be referenced using the later <taskID> syntax.
Metadata syntax Start date End date ID
<taskID>, <startDate>, <endDate> startdate as interpreted using dateformat endDate as interpreted using dateformat taskID
<taskID>, <startDate>, <length> startdate as interpreted using dateformat Start date + length taskID
<taskID>, after <otherTaskId>, <endDate> End date of previously specified task otherTaskID endDate as interpreted using dateformat taskID
<taskID>, after <otherTaskId>, <length> End date of previously specified task otherTaskID Start date + length taskID
<taskID>, <startDate>, until <otherTaskId> startdate as interpreted using dateformat Start date of previously specified task otherTaskID taskID
<taskID>, after <otherTaskId>, until <otherTaskId> End date of previously specified task otherTaskID Start date of previously specified task otherTaskID taskID
<startDate>, <endDate> startdate as interpreted using dateformat enddate as interpreted using dateformat n/a
<startDate>, <length> startdate as interpreted using dateformat Start date + length n/a
after <otherTaskID>, <endDate> End date of previously specified task otherTaskID enddate as interpreted using dateformat n/a
after <otherTaskID>, <length> End date of previously specified task otherTaskID Start date + length n/a
<startDate>, until <otherTaskId> startdate as interpreted using dateformat Start date of previously specified task otherTaskID n/a
after <otherTaskId>, until <otherTaskId> End date of previously specified task otherTaskID Start date of previously specified task otherTaskID n/a
<endDate> End date of preceding task enddate as interpreted using dateformat n/a
<length> End date of preceding task Start date + length n/a
until <otherTaskId> End date of preceding task Start date of previously specified task otherTaskID n/a

Note

Support for keyword until was added in (v10.9.0+). This can be used to define a task which is running until some other specific task or milestone starts.

Duration format

When specifying a <length>, use a number followed by one of these unit suffixes:

Unit Suffix Example
Milliseconds ms 500ms
Seconds s 30s
Minutes m 30m
Hours h 4h
Days d 3d
Weeks w 2w
Months M 1M
Years y 1y

Decimal values are also supported (e.g., 1.5d). Invalid duration tokens (e.g., 3dX) will be ignored and the task will default to zero duration.

For simplicity, the table does not show the use of multiple tasks listed with the after keyword. Here is an example of how to use it and how it's interpreted:

gantt
    apple :a, 2017-07-20, 1w
    banana :crit, b, 2017-07-23, 1d
    cherry :active, c, after b a, 1d
    kiwi   :d, 2017-07-20, until b c
gantt
    apple :a, 2017-07-20, 1w
    banana :crit, b, 2017-07-23, 1d
    cherry :active, c, after b a, 1d
    kiwi   :d, 2017-07-20, until b c

Title

The title is an optional string to be displayed at the top of the Gantt chart to describe the chart as a whole.

Excludes

The excludes is an optional attribute that accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays". These date will be marked on the graph, and be excluded from the duration calculation of tasks. Meaning that if there are excluded dates during a task interval, the number of 'skipped' days will be added to the end of the task to ensure the duration is as specified in the code.

Weekend (v\11.0.0+)

When excluding weekends, it is possible to configure the weekends to be either Friday and Saturday or Saturday and Sunday. By default weekends are Saturday and Sunday. To define the weekend start day, there is an optional attribute weekend that can be added in a new line followed by either friday or saturday.

gantt
    title A Gantt Diagram Excluding Fri - Sat weekends
    dateFormat YYYY-MM-DD
    excludes weekends
    weekend friday
    section Section
        A task          :a1, 2024-01-01, 30d
        Another task    :after a1, 20d
gantt
    title A Gantt Diagram Excluding Fri - Sat weekends
    dateFormat YYYY-MM-DD
    excludes weekends
    weekend friday
    section Section
        A task          :a1, 2024-01-01, 30d
        Another task    :after a1, 20d

Section statements

You can divide the chart into various sections, for example to separate different parts of a project like development and documentation.

To do so, start a line with the section keyword and give it a name. (Note that unlike with the title for the entire chart, this name is required.

Milestones

You can add milestones to the diagrams. Milestones differ from tasks as they represent a single instant in time and are identified by the keyword milestone. Below is an example on how to use milestones. As you may notice, the exact location of the milestone is determined by the initial date for the milestone and the "duration" of the task this way: initial date+duration/2.

gantt
    dateFormat HH:mm
    axisFormat %H:%M
    Initial milestone : milestone, m1, 17:49, 2m
    Task A : 10m
    Task B : 5m
    Final milestone : milestone, m2, 18:08, 4m
gantt
    dateFormat HH:mm
    axisFormat %H:%M
    Initial milestone : milestone, m1, 17:49, 2m
    Task A : 10m
    Task B : 5m
    Final milestone : milestone, m2, 18:08, 4m

Vertical Markers

The vert keyword lets you add vertical lines to your Gantt chart, making it easy to highlight important dates like deadlines, events, or checkpoints. These markers extend across the entire chart and are positioned based on the date you provide. Unlike milestones, vertical markers dont take up a row. Theyre purely visual reference points that help break up the timeline and make important moments easier to spot.

gantt
    dateFormat HH:mm
    axisFormat %H:%M
    Initial vert : vert, v1, 17:30, 2m
    Task A : 3m
    Task B : 8m
    Final vert : vert, v2, 17:58, 4m
gantt
    dateFormat HH:mm
    axisFormat %H:%M
    Initial vert : vert, v1, 17:30, 2m
    Task A : 3m
    Task B : 8m
    Final vert : vert, v2, 17:58, 4m

Setting dates

dateFormat defines the format of the date input of your gantt elements. How these dates are represented in the rendered chart output are defined by axisFormat.

Input date format

The default input date format is YYYY-MM-DD. You can define your custom dateFormat.

dateFormat YYYY-MM-DD

The following formatting options are supported:

Input Example Description
YYYY 2014 4 digit year
YY 14 2 digit year
Q 1..4 Quarter of year. Sets month to first month in quarter.
M MM 1..12 Month number
MMM MMMM January..Dec Month name in locale set by dayjs.locale()
D DD 1..31 Day of month
Do 1st..31st Day of month with ordinal
DDD DDDD 1..365 Day of year
X 1410715640.579 Unix timestamp
x 1410715640579 Unix ms timestamp
H HH 0..23 24 hour time
h hh 1..12 12 hour time used with a A.
a A am pm Post or ante meridiem
m mm 0..59 Minutes
s ss 0..59 Seconds
S 0..9 Tenths of a second
SS 0..99 Hundreds of a second
SSS 0..999 Thousandths of a second
Z ZZ +12:00 Offset from UTC as +-HH:mm, +-HHmm, or Z

More info in: https://day.js.org/docs/en/parse/string-format/

Output date format on the axis

The default output date format is YYYY-MM-DD. You can define your custom axisFormat, like 2020-Q1 for the first quarter of the year 2020.

axisFormat %Y-%m-%d

The following formatting strings are supported:

Format Definition
%a abbreviated weekday name
%A full weekday name
%b abbreviated month name
%B full month name
%c date and time, as "%a %b %e %H:%M:%S %Y"
%d zero-padded day of the month as a decimal number [01,31]
%e space-padded day of the month as a decimal number [ 1,31]; equivalent to %_d
%H hour (24-hour clock) as a decimal number [00,23]
%I hour (12-hour clock) as a decimal number [01,12]
%j day of the year as a decimal number [001,366]
%m month as a decimal number [01,12]
%M minute as a decimal number [00,59]
%L milliseconds as a decimal number [000, 999]
%p either AM or PM
%S second as a decimal number [00,61]
%U week number of the year (Sunday as the first day of the week) as a decimal number [00,53]
%w weekday as a decimal number [0(Sunday),6]
%W week number of the year (Monday as the first day of the week) as a decimal number [00,53]
%x date, as "%m/%d/%Y"
%X time, as "%H:%M:%S"
%y year without century as a decimal number [00,99]
%Y year with century as a decimal number
%Z time zone offset, such as "-0700"
%% a literal "%" character

More info in: https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format

Axis ticks (v10.3.0+)

The default output ticks are auto. You can custom your tickInterval, like 1day or 1week.

tickInterval 1day

The pattern is:

/^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/;

More info in: https://github.com/d3/d3-time#interval_every

Week-based tickIntervals start the week on sunday by default. If you wish to specify another weekday on which the tickInterval should start, use the weekday option:

gantt
  tickInterval 1week
  weekday monday
gantt
  tickInterval 1week
  weekday monday

Warning

millisecond and second support was added in v10.3.0

Output in compact mode

The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceding YAML settings.

---
displayMode: compact
---
gantt
    title A Gantt Diagram
    dateFormat  YYYY-MM-DD

    section Section
    A task           :a1, 2014-01-01, 30d
    Another task     :a2, 2014-01-20, 25d
    Another one      :a3, 2014-02-10, 20d
---
displayMode: compact
---
gantt
    title A Gantt Diagram
    dateFormat  YYYY-MM-DD

    section Section
    A task           :a1, 2014-01-01, 30d
    Another task     :a2, 2014-01-20, 25d
    Another one      :a3, 2014-02-10, 20d

Comments

Comments can be entered within a gantt chart, which will be ignored by the parser. Comments need to be on their own line and must be prefaced with %% (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax.

gantt
    title A Gantt Diagram
    %% This is a comment
    dateFormat YYYY-MM-DD
    section Section
        A task          :a1, 2014-01-01, 30d
        Another task    :after a1, 20d
    section Another
        Task in Another :2014-01-12, 12d
        another task    :24d
gantt
    title A Gantt Diagram
    %% This is a comment
    dateFormat YYYY-MM-DD
    section Section
        A task          :a1, 2014-01-01, 30d
        Another task    :after a1, 20d
    section Another
        Task in Another :2014-01-12, 12d
        another task    :24d

Styling

Styling of the Gantt diagram is done by defining a number of CSS classes. During rendering, these classes are extracted from the file located at src/diagrams/gantt/styles.js

Classes used

Class Description
grid.tick Styling for the Grid Lines
grid.path Styling for the Grid's borders
.taskText Task Text Styling
.taskTextOutsideRight Styling for Task Text that exceeds the activity bar towards the right.
.taskTextOutsideLeft Styling for Task Text that exceeds the activity bar, towards the left.
todayMarker Toggle and Styling for the "Today Marker"

Sample stylesheet

.grid .tick {
  stroke: lightgrey;
  opacity: 0.3;
  shape-rendering: crispEdges;
}
.grid path {
  stroke-width: 0;
}

#tag {
  color: white;
  background: #fa283d;
  width: 150px;
  position: absolute;
  display: none;
  padding: 3px 6px;
  margin-left: -80px;
  font-size: 11px;
}

#tag:before {
  border: solid transparent;
  content: ' ';
  height: 0;
  left: 50%;
  margin-left: -5px;
  position: absolute;
  width: 0;
  border-width: 10px;
  border-bottom-color: #fa283d;
  top: -20px;
}
.taskText {
  fill: white;
  text-anchor: middle;
}
.taskTextOutsideRight {
  fill: black;
  text-anchor: start;
}
.taskTextOutsideLeft {
  fill: black;
  text-anchor: end;
}

Today marker

You can style or hide the marker for the current date. To style it, add a value for the todayMarker key.

todayMarker stroke-width:5px,stroke:#0f0,opacity:0.5

To hide the marker, set todayMarker to off.

todayMarker off

Configuration

It is possible to adjust the margins for rendering the gantt diagram.

This is done by defining the ganttConfig part of the configuration object. How to use the CLI is described in the mermaidCLI page.

mermaid.ganttConfig can be set to a JSON string with config parameters or the corresponding object.

mermaid.ganttConfig = {
  titleTopMargin: 25, // Margin top for the text over the diagram
  barHeight: 20, // The height of the bars in the graph
  barGap: 4, // The margin between the different activities in the gantt diagram
  topPadding: 75, // Margin between title and gantt diagram and between axis and gantt diagram.
  rightPadding: 75, // The space allocated for the section name to the right of the activities
  leftPadding: 75, // The space allocated for the section name to the left of the activities
  gridLineStartPadding: 10, // Vertical starting position of the grid lines
  fontSize: 12, // Font size
  sectionFontSize: 24, // Font size for sections
  numberSectionStyles: 1, // The number of alternating section styles
  axisFormat: '%d/%m', // Date/time format of the axis
  tickInterval: '1week', // Axis ticks
  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
  displayMode: 'compact', // Turns compact mode on
  weekday: 'sunday', // On which day a week-based interval should start
};

Possible configuration params:

Param Description Default value
mirrorActor Turns on/off the rendering of actors below the diagram as well as above it false
bottomMarginAdj Adjusts how far down the graph ended. Wide borders styles with css could generate unwanted clipping which is why this config param exists. 1

Interaction

It is possible to bind a click event to a task. The click can lead to either a javascript callback or to a link which will be opened in the current browser tab. Note: This functionality is disabled when using securityLevel='strict' and enabled when using securityLevel='loose'.

click taskId call callback(arguments)
click taskId href URL
  • taskId is the id of the task
  • callback is the name of a javascript function defined on the page displaying the graph, the function will be called with the taskId as the parameter if no other arguments are specified.

Beginner's tip—a full example using interactive links in an HTML context:

<body>
  <pre class="mermaid">
    gantt
      dateFormat  YYYY-MM-DD

      section Clickable
      Visit mermaidjs         :active, cl1, 2014-01-07, 3d
      Print arguments         :cl2, after cl1, 3d
      Print task              :cl3, after cl2, 3d

      click cl1 href "https://mermaidjs.github.io/"
      click cl2 call printArguments("test1", "test2", test3)
      click cl3 call printTask()
  </pre>

  <script>
    const printArguments = function (arg1, arg2, arg3) {
      alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);
    };
    const printTask = function (taskId) {
      alert('taskId: ' + taskId);
    };
    const config = {
      startOnLoad: true,
      securityLevel: 'loose',
    };
    mermaid.initialize(config);
  </script>
</body>

Examples

Bar chart (using gantt chart)

gantt
    title Git Issues - days since last update
    dateFormat X
    axisFormat %s
    section Issue19062
    71   : 0, 71
    section Issue19401
    36   : 0, 36
    section Issue193
    34   : 0, 34
    section Issue7441
    9    : 0, 9
    section Issue1300
    5    : 0, 5
gantt
    title Git Issues - days since last update
    dateFormat X
    axisFormat %s
    section Issue19062
    71   : 0, 71
    section Issue19401
    36   : 0, 36
    section Issue193
    34   : 0, 34
    section Issue7441
    9    : 0, 9
    section Issue1300
    5    : 0, 5

Timeline (with comments, CSS, config in frontmatter)

---
    # Frontmatter config, YAML comments
    title: Ignored if specified in chart
    displayMode: compact     #gantt specific setting but works at this level too
    config:
#        theme: forest
#        themeCSS: " #item36 { fill: CadetBlue } "
        themeCSS: " // YAML supports multiline strings using a newline markers: \n
            #item36 { fill: CadetBlue }       \n

            // Custom marker workaround CSS from forum (below)    \n
            rect[id^=workaround] { height: calc(100% - 50px) ; transform: translate(9px, 25px); y: 0; width: 1.5px; stroke: none; fill: red; }   \n
            text[id^=workaround] { fill: red; y: 100%; font-size: 15px;}
        "
        gantt:
            useWidth: 400
            rightPadding: 0
            topAxis: true  #false
            numberSectionStyles: 2
---
gantt
    title Timeline - Gantt Sampler
    dateFormat YYYY
    axisFormat %y
    %% this next line doesn't recognise 'decade' or 'year', but will silently ignore
    tickInterval 1decade

    section Issue19062
    71   :            item71, 1900, 1930
    section Issue19401
    36   :            item36, 1913, 1935
    section Issue1300
    94   :            item94, 1910, 1915
    5    :            item5,  1920, 1925
    0    : milestone, item0,  1918, 1s
    9    : vert,              1906, 1s   %% not yet official
    64   : workaround,        1923, 1s   %% custom CSS object https://github.com/mermaid-js/mermaid/issues/3250
---
    # Frontmatter config, YAML comments
    title: Ignored if specified in chart
    displayMode: compact     #gantt specific setting but works at this level too
    config:
#        theme: forest
#        themeCSS: " #item36 { fill: CadetBlue } "
        themeCSS: " // YAML supports multiline strings using a newline markers: \n
            #item36 { fill: CadetBlue }       \n

            // Custom marker workaround CSS from forum (below)    \n
            rect[id^=workaround] { height: calc(100% - 50px) ; transform: translate(9px, 25px); y: 0; width: 1.5px; stroke: none; fill: red; }   \n
            text[id^=workaround] { fill: red; y: 100%; font-size: 15px;}
        "
        gantt:
            useWidth: 400
            rightPadding: 0
            topAxis: true  #false
            numberSectionStyles: 2
---
gantt
    title Timeline - Gantt Sampler
    dateFormat YYYY
    axisFormat %y
    %% this next line doesn't recognise 'decade' or 'year', but will silently ignore
    tickInterval 1decade

    section Issue19062
    71   :            item71, 1900, 1930
    section Issue19401
    36   :            item36, 1913, 1935
    section Issue1300
    94   :            item94, 1910, 1915
    5    :            item5,  1920, 1925
    0    : milestone, item0,  1918, 1s
    9    : vert,              1906, 1s   %% not yet official
    64   : workaround,        1923, 1s   %% custom CSS object https://github.com/mermaid-js/mermaid/issues/3250