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 --> [*] : Delete
Try 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 --> [*] : Delivered
Try 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 --> [*] : Terminate
Try 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 note
Try 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 --> [*] : Unmount
Try 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 activeState
Try 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

  1. Always include start and end states ([*]) to clearly show entry and exit points.
  1. Name states as nouns or adjectives — "Processing", "Active", "WaitingForApproval" — not verbs.
  1. Label transitions as events or actions — "click submit", "payment received", "timeout" — verbs or events that trigger the change.
  1. Use composite states to manage complexity. A 20-state flat diagram becomes readable when grouped into 3-4 composite states.
  1. Model error states explicitly. Don't just show the happy path — document how the system handles failures and recovers.
  1. Use choice states for conditional branching instead of multiple transitions from one state with the same trigger.
  1. 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.

Try it now in our free Mermaid Live Editor →