



JavaScript state machines and statecharts





JavaScript and TypeScript finite state machines and statecharts for the modern web.

📖 Read the documentation 📑 Adheres to the SCXML specification .

🤖 xstate - Core finite state machine and statecharts library + interpreter

- Core finite state machine and statecharts library + interpreter 🔬 @xstate/fsm - Minimal finite state machine library

- Minimal finite state machine library 📉 @xstate/graph - Graph traversal utilities for XState

- Graph traversal utilities for XState ⚛️ @xstate/react - React hooks and utilities for using XState in React applications

- React hooks and utilities for using XState in React applications 💚 @xstate/vue - Vue composition functions and utilities for using XState in Vue applications

- Vue composition functions and utilities for using XState in Vue applications ✅ @xstate/test - Model-based testing utilities for XState

Get started by forking one of these templates on CodeSandbox:

# Super quick start

npm install xstate

import { createMachine , interpret } from 'xstate' ; const toggleMachine = createMachine ( { id : 'toggle' , initial : 'inactive' , states : { inactive : { on : { TOGGLE : 'active' } } , active : { on : { TOGGLE : 'inactive' } } } } ) ; const toggleService = interpret ( toggleMachine ) . onTransition ( ( state ) => console . log ( state . value ) ) . start ( ) ; toggleService . send ( 'TOGGLE' ) ; toggleService . send ( 'TOGGLE' ) ;

# Promise example

📉 See the visualization on xstate.js.org/viz

import { createMachine , interpret , assign } from 'xstate' ; const fetchMachine = createMachine ( { id : 'SWAPI' , initial : 'idle' , context : { user : null } , states : { idle : { on : { FETCH : 'loading' } } , loading : { invoke : { id : 'fetchLuke' , src : ( context , event ) => fetch ( 'https://swapi.dev/api/people/1' ) . then ( ( res ) => res . data ) , onDone : { target : 'resolved' , actions : assign ( { user : ( _ , event ) => event . data } ) } , onError : 'rejected' } , on : { CANCEL : 'idle' } } , resolved : { type : 'final' } , rejected : { on : { FETCH : 'loading' } } } } ) ; const swService = interpret ( fetchMachine ) . onTransition ( ( state ) => console . log ( state . value ) ) . start ( ) ; swService . send ( 'FETCH' ) ;

Visualize, simulate, and share your statecharts in XState Viz!

Statecharts are a formalism for modeling stateful, reactive systems. This is useful for declaratively describing the behavior of your application, from the individual components to the overall application logic.

Read 📽 the slides (🎥 video ) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:

# Finite State Machines

import { Machine } from 'xstate' ; const lightMachine = Machine ( { id : 'light' , initial : 'green' , states : { green : { on : { TIMER : 'yellow' } } , yellow : { on : { TIMER : 'red' } } , red : { on : { TIMER : 'green' } } } } ) ; const currentState = 'green' ; const nextState = lightMachine . transition ( currentState , 'TIMER' ) . value ;

# Hierarchical (Nested) State Machines

import { Machine } from 'xstate' ; const pedestrianStates = { initial : 'walk' , states : { walk : { on : { PED_TIMER : 'wait' } } , wait : { on : { PED_TIMER : 'stop' } } , stop : { } } } ; const lightMachine = Machine ( { id : 'light' , initial : 'green' , states : { green : { on : { TIMER : 'yellow' } } , yellow : { on : { TIMER : 'red' } } , red : { on : { TIMER : 'green' } , ... pedestrianStates } } } ) ; const currentState = 'yellow' ; const nextState = lightMachine . transition ( currentState , 'TIMER' ) . value ; lightMachine . transition ( 'red.walk' , 'PED_TIMER' ) . value ;

Object notation for hierarchical states:

const waitState = lightMachine . transition ( { red : 'walk' } , 'PED_TIMER' ) . value ; lightMachine . transition ( waitState , 'PED_TIMER' ) . value ; lightMachine . transition ( { red : 'stop' } , 'TIMER' ) . value ;

# Parallel State Machines

const wordMachine = Machine ( { id : 'word' , type : 'parallel' , states : { bold : { initial : 'off' , states : { on : { on : { TOGGLE_BOLD : 'off' } } , off : { on : { TOGGLE_BOLD : 'on' } } } } , underline : { initial : 'off' , states : { on : { on : { TOGGLE_UNDERLINE : 'off' } } , off : { on : { TOGGLE_UNDERLINE : 'on' } } } } , italics : { initial : 'off' , states : { on : { on : { TOGGLE_ITALICS : 'off' } } , off : { on : { TOGGLE_ITALICS : 'on' } } } } , list : { initial : 'none' , states : { none : { on : { BULLETS : 'bullets' , NUMBERS : 'numbers' } } , bullets : { on : { NONE : 'none' , NUMBERS : 'numbers' } } , numbers : { on : { BULLETS : 'bullets' , NONE : 'none' } } } } } } ) ; const boldState = wordMachine . transition ( 'bold.off' , 'TOGGLE_BOLD' ) . value ; const nextState = wordMachine . transition ( { bold : 'off' , italics : 'off' , underline : 'on' , list : 'bullets' } , 'TOGGLE_ITALICS' ) . value ;

# History States

const paymentMachine = Machine ( { id : 'payment' , initial : 'method' , states : { method : { initial : 'cash' , states : { cash : { on : { SWITCH_CHECK : 'check' } } , check : { on : { SWITCH_CASH : 'cash' } } , hist : { type : 'history' } } , on : { NEXT : 'review' } } , review : { on : { PREVIOUS : 'method.hist' } } } } ) ; const checkState = paymentMachine . transition ( 'method.cash' , 'SWITCH_CHECK' ) ; const reviewState = paymentMachine . transition ( checkState , 'NEXT' ) ; const previousState = paymentMachine . transition ( reviewState , 'PREVIOUS' ) . value ;