State diagrams

stateDiagram-v2 opens a state diagram. There is no in-diagram direction keyword; the author default is top-to-bottom. With a Viewport, responsive layout may flip wide diagrams to horizontal so they use available width (same rules as flowcharts). Without a viewport, layout stays vertical.

MermoidAscent.svgDiagram(orderFsm)
payment capturedcustomer cancelscarrier acceptsscanPendingCancelledPaidShippedDelivered

Transitions

From --> To declares a transition; : label names it. States do not need declaring — every id mentioned by a transition becomes a state, rendered as a Round node labelled with its own id.

MermoidAscent.svgDiagram("""stateDiagram-v2
    Idle --> Running: start
    Running --> Idle: stop
""".stripMargin)
startstopRunningIdle

That is a two-state cycle, and it lays out rather than looping forever — layering breaks cycles.

Start and end

[*] is the start/end pseudo-state: a filled 16×16 circle carrying the start-end class, with no label. Whether it reads as start or end is positional: [*] --> A versus A --> [*].

When a diagram uses both, mermoid paints two markers (start keeps id [*], end is [*]-end) so ranking does not cycle through a shared node and flip the layout. A diagram that only has one role still uses a single [*] node.

MermoidAscent.svgDiagram("""stateDiagram-v2
    [*] --> Active
    Active --> [*]
""".stripMargin)
Active

Notes

note right of Idle
  waiting for work
end note

right of and left of are both supported. Note text is multi-line; each line is trimmed and blank lines dropped. A note renders as a dashed box joined to its state by a dashed connector, and the diagram's bounding box grows to hold it, including shifting the whole diagram right when a left of note would otherwise fall outside the canvas.

When the preferred side would overlap another node (common in horizontal / flipped layouts), the placer tries the other side and then a vertical offset before settling.

MermoidAscent.svgDiagram("""stateDiagram-v2
    [*] --> Idle
    Idle --> Running: start
    Running --> Idle: finish
    note right of Idle
      no work in flight
      polls every 5s
    end note
    note left of Running
      at most one job
    end note
""".stripMargin)
startfinishRunningIdleno work in flightpolls every 5sat most one job

Styling from the diagram source

classDef, class, :::, and style are the same statements as on flowcharts. classDef becomes a CSS rule, class / ::: put the name on the state's node, and style can still set noteAlign as well as fill and stroke.

MermoidAscent.svgDiagram("""stateDiagram-v2
    classDef happy fill:#1f4a35,stroke:#7dcea0
    classDef warn fill:#4a4030,stroke:#e0c070
    classDef sad fill:#5c2a2a,stroke:#f0a0a0
    [*] --> Green
    Green --> Yellow: Timer
    Yellow --> Red: Timer
    Red --> Green: Timer
    class Green happy
    class Yellow warn
    class Red sad
""".stripMargin)
TimerTimerTimerYellowRedGreen

Green:::happy --> Yellow:::warn is the same assignment written on the transition.

Note text alignment

style <state> noteAlign: left | center | right sets how that state's note text is aligned. The default is left.

MermoidAscent.svgDiagram("""stateDiagram-v2
    [*] --> Ready
    Ready --> Done: go
    style Ready noteAlign: center
    note right of Ready
      centered
      note text
    end note
""".stripMargin)
goReadyDonecenterednote text

Note aliases

Like edges, notes take as <name> to pin their element id. Without it a note is note-{stateId}-{index}, so adding an earlier note on the same state renumbers the later ones.

MermoidAscent.svgDiagram("""stateDiagram-v2
    [*] --> Idle
    Idle --> Done: go
    note right of Idle as caveat
      do not skip idle
    end note
""".stripMargin)
goIdleDonedo not skip idle

Self-transitions

A state can transition to itself, and stacked self-transitions stack their labels. The diagram's height accounts for the loops, and for notes pushed below them.

MermoidAscent.svgDiagram("""stateDiagram-v2
    [*] --> Retrying
    Retrying --> Retrying: attempt failed
    Retrying --> Retrying: backoff elapsed
    Retrying --> Done: succeeded
""".stripMargin)
attempt failedbackoff elapsedsucceededRetryingDone

Not yet implemented

Composite (nested) states, concurrency (--), an in-diagram direction, and state X as "long name" declarations are not implemented. click is flowchart-only; state diagrams have no click statement. A state diagram that needs nesting can be expressed as a flowchart with subgraphs today.