Mermaid State Diagrams — Complete Tutorial
Create state machine diagrams with Mermaid.js. Learn states, transitions, guards, composite states, forks, joins, and real-world examples.
What Are State Diagrams?
State diagrams (also called state machine diagrams or statecharts) show the different states an object or system can be in, and the transitions between those states. They're essential for modeling:
- UI component states (loading, error, success)
- Order lifecycles (pending, processing, shipped, delivered)
- Authentication flows (logged out, logging in, authenticated, expired)
- Game states (menu, playing, paused, game over)
- Network connections (disconnected, connecting, connected)
Basic Syntax
stateDiagram-v2
[*] --> Idle
Idle --> Processing : Start
Processing --> Completed : Success
Processing --> Failed : Error
Failed --> Idle : Retry
Completed --> [*]Try in Editor →Key elements:
- [*] — Start state (filled circle) or end state
- --> — Transition arrow
- Text after : is the trigger/event label
- State names are automatically rendered as rounded rectangles
Defining States
Simple States
stateDiagram-v2
[*] --> Active
Active --> Inactive : Deactivate
Inactive --> Active : Activate
Active --> [*] : DeleteTry in Editor →States with Descriptions
stateDiagram-v2
state "Waiting for Payment" as WFP
state "Order Confirmed" as OC
state "Shipped to Customer" as STC
[*] --> WFP
WFP --> OC : Payment received
OC --> STC : Dispatched
STC --> [*] : DeliveredTry in Editor →Use the state "description" as alias syntax for multi-word state names.
Transitions
Labeled Transitions
stateDiagram-v2
Idle --> Running : start()
Running --> Idle : stop()
Running --> Running : process(item)
Running --> Error : exception thrown
Error --> Idle : reset()Try in Editor →Self-Transitions
A state can transition to itself (like "Running → Running" above). This represents an event that's handled without changing state.
Composite (Nested) States
Group related states inside a parent state:
stateDiagram-v2
[*] --> Active
state Active {
[*] --> Idle
Idle --> Processing : Request
Processing --> Idle : Complete
Processing --> Error : Fail
Error --> Idle : Retry
}
Active --> Suspended : Suspend
Suspended --> Active : Resume
Active --> [*] : TerminateTry in Editor →This shows that Active has its own internal states. The system can be suspended from any Active sub-state and resume back.
Deeply Nested States
stateDiagram-v2
[*] --> App
state App {
[*] --> Auth
state Auth {
[*] --> LoggedOut
LoggedOut --> LoggingIn : Enter credentials
LoggingIn --> LoggedIn : Valid
LoggingIn --> LoggedOut : Invalid
}
state LoggedIn {
[*] --> Dashboard
Dashboard --> Settings : Open settings
Settings --> Dashboard : Back
}
Auth --> LoggedIn : Authenticated
LoggedIn --> Auth : Logout
}Try in Editor →Practical Example: Order Lifecycle
stateDiagram-v2
[*] --> Draft
Draft --> Submitted : Customer places order
Submitted --> PaymentPending : Order validated
state PaymentPending {
[*] --> AwaitingPayment
AwaitingPayment --> ProcessingPayment : Payment initiated
ProcessingPayment --> PaymentConfirmed : Success
ProcessingPayment --> PaymentFailed : Declined
PaymentFailed --> AwaitingPayment : Retry
}
PaymentPending --> Cancelled : Customer cancels
PaymentConfirmed --> Fulfillment
state Fulfillment {
[*] --> Picking
Picking --> Packing : Items collected
Packing --> ReadyToShip : Packed
}
ReadyToShip --> Shipped : Carrier pickup
Shipped --> Delivered : Delivery confirmed
Delivered --> [*]
Shipped --> ReturnRequested : Customer requests return
ReturnRequested --> Returned : Return received
Returned --> [*]
Draft --> Cancelled : Customer cancels
Submitted --> Cancelled : Validation failed
Cancelled --> [*]Try in Editor →Choice (Decision) States
Show conditional branching:
stateDiagram-v2
[*] --> RequestReceived
RequestReceived --> ValidatingInput
ValidatingInput --> CheckAuth
state CheckAuth <<choice>>
CheckAuth --> Authorized : Token valid
CheckAuth --> Unauthorized : Token invalid
Authorized --> Processing
Processing --> Success
Success --> [*]
Unauthorized --> [*]Try in Editor →Fork and Join (Parallel States)
Show concurrent execution:
stateDiagram-v2
[*] --> OrderPlaced
state fork_state <<fork>>
OrderPlaced --> fork_state
fork_state --> SendEmail
fork_state --> ProcessPayment
fork_state --> UpdateInventory
state join_state <<join>>
SendEmail --> join_state
ProcessPayment --> join_state
UpdateInventory --> join_state
join_state --> OrderComplete
OrderComplete --> [*]Try in Editor →This models three activities happening in parallel after an order is placed, with all three needing to complete before the order is marked complete.
Notes
Add context with notes:
stateDiagram-v2
[*] --> Active
Active --> Inactive
note right of Active
System is processing
requests in this state
end note
note left of Inactive
All connections closed.
Resources released.
end noteTry in Editor →Practical Example: UI Component States
stateDiagram-v2
[*] --> Initial
state Initial {
[*] --> Empty
}
Initial --> Loading : fetch()
Loading --> Success : Data received
Loading --> Error : Request failed
state Success {
[*] --> DisplayingData
DisplayingData --> Refreshing : Pull to refresh
Refreshing --> DisplayingData : Updated
}
state Error {
[*] --> ShowError
ShowError --> ShowError : Display message
}
Error --> Loading : Retry
Success --> Loading : Refresh
Success --> [*] : Unmount
Error --> [*] : UnmountTry in Editor →Styling
Apply CSS-like styles:
stateDiagram-v2
[*] --> Active
Active --> Error
Error --> Active
classDef errorState fill:#ff6b6b,color:white,stroke:#c0392b
classDef activeState fill:#51cf66,color:white,stroke:#2f9e44
class Error errorState
class Active activeStateTry in Editor →Direction
Control layout direction:
stateDiagram-v2
direction LR
[*] --> A --> B --> C --> [*]Try in Editor →Options: TB (top-bottom, default), LR (left-right), BT, RL.
Best Practices
- Always include start and end states (
[*]) to clearly show entry and exit points.
- Name states as nouns or adjectives — "Processing", "Active", "WaitingForApproval" — not verbs.
- Label transitions as events or actions — "click submit", "payment received", "timeout" — verbs or events that trigger the change.
- Use composite states to manage complexity. A 20-state flat diagram becomes readable when grouped into 3-4 composite states.
- Model error states explicitly. Don't just show the happy path — document how the system handles failures and recovers.
- Use choice states for conditional branching instead of multiple transitions from one state with the same trigger.
- Keep it focused. One state diagram per concern. Don't try to model your entire application in a single diagram.
Conclusion
State diagrams are invaluable for documenting system behavior — especially for anything with a lifecycle (orders, sessions, UI states, workflows). Mermaid's text syntax makes them easy to create and maintain in your documentation. Start with the basic states and transitions, then add composite states and parallel execution as complexity grows.