State Machine

Manage complex workflows with state machines
Learn how to implement state machines using hyperscript for managing multi-step processes, workflows, and complex UI states. Perfect for checkout flows, wizards, and game logic!
state management workflows transitions guards

Order Processing State Machine

This demo shows a complete order workflow with state transitions and guards:

State Flow

Cart
Add items to cart
Checkout
Review order details
Payment
Enter payment info
Processing
Processing payment
Completed
Order confirmed
Cancelled
Order cancelled
Current State: Shopping Cart
Click buttons to transition between states

Order Summary

Subtotal: $0.00
Shipping: $10.00
Tax: $12.00
Total: $151.99
State History

The Code

State Machine Initialization:

<div id="state-machine" _="init set :state to 'idle' set :data to {} end on updateUI -- Update UI based on current state for box in .state-box remove .active from box end add .active to #state-{:state} end"> </div>

State Transition with Guard:

<button _="on click -- Guard: Check if transition is allowed if :state is 'checkout' and :paymentValid set :state to 'payment' send updateUI to #state-machine else log 'Cannot transition: conditions not met' end"> Next Step </button>

State Transition Handler:

<div _="on checkout if :state is 'cart' set :state to 'checkout' call :history.push({ from: 'cart', to: 'checkout', timestamp: Date.now() }) send updateUI end end"> </div>

How it works:

Key Concepts:

State Machine Pattern:

-- Define states set :states to ['idle', 'loading', 'success', 'error'] -- Define allowed transitions set :transitions to { idle: ['loading'], loading: ['success', 'error'], success: ['idle'], error: ['idle'] } -- Transition with validation on transition(newState) if :transitions[:state].includes(newState) set oldState to :state set :state to newState -- Execute exit action for old state send exitState(oldState) -- Execute entry action for new state send enterState(newState) -- Update UI send updateUI else log 'Invalid transition from ' + :state + ' to ' + newState end end

Advanced Patterns:

<!-- Nested state machines --> <div _="init set :parentState to 'active' set :childState to 'editing' end on transition(newState) if newState is in :allowedStates set :parentState to newState -- Reset child state on parent transition set :childState to getInitialChildState(newState) end end"> </div> <!-- State machine with history --> <div _="init set :stateStack to ['idle'] end on pushState(newState) call :stateStack.push(:state) set :state to newState send updateUI end on popState if :stateStack.length > 0 set :state to :stateStack.pop() send updateUI end end"> </div> <!-- Timed transitions --> <div _="on enterState(state) if state is 'processing' wait 5s if :state is still 'processing' send transition('timeout') end end end"> </div> <!-- Parallel states --> <div _="init set :connectionState to 'disconnected' set :authState to 'unauthenticated' set :dataState to 'empty' end on connect set :connectionState to 'connected' if :authState is 'authenticated' send loadData end end"> </div>

Common Use Cases:

Benefits of State Machines:

State Machine Best Practices:

Try it yourself: