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.
Packages
- 🤖
xstate- Core finite state machine and statecharts library + interpreter - 🔬
@xstate/fsm- Minimal finite state machine library - 📉
@xstate/graph- Graph traversal utilities for XState - ⚛️
@xstate/react- React hooks and utilities for using XState in React applications - ✅
@xstate/test- Model-based testing utilities for XState
Super quick start
npm install xstate
import { createMachine, interpret } from 'xstate';// Stateless machine definition// machine.transition(...) is a pure function used by the interpreter.const toggleMachine = createMachine({id: 'toggle',initial: 'inactive',states: {inactive: { on: { TOGGLE: 'active' } },active: { on: { TOGGLE: 'inactive' } }}});// Machine instance with internal stateconst toggleService = interpret(toggleMachine).onTransition((state) => console.log(state.value)).start();// => 'inactive'toggleService.send('TOGGLE');// => 'active'toggleService.send('TOGGLE');// => 'inactive'
- Visualizer
- Why? (info about statecharts)
- Installation
- Finite State Machines
- Hierarchical (Nested) State Machines
- Parallel State Machines
- History States
Visualizer
Visualize, simulate, and share your statecharts in XState Viz!
Why?
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:
- Statecharts - A Visual Formalism for Complex Systems by David Harel
- The World of Statecharts by Erik Mogensen
- Pure UI by Guillermo Rauch
- Pure UI Control by Adam Solove
- Spectrum - Statecharts Community (For XState specific questions, please use the GitHub Discussions)
Finite State Machines

import { createMachine } from 'xstate';const lightMachine = createMachine({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;// => 'yellow'
Hierarchical (Nested) State Machines

import { createMachine } from 'xstate';const pedestrianStates = {initial: 'walk',states: {walk: {on: {PED_TIMER: 'wait'}},wait: {on: {PED_TIMER: 'stop'}},stop: {}}};const lightMachine = createMachine({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;// => {// red: 'walk'// }lightMachine.transition('red.walk', 'PED_TIMER').value;// => {// red: 'wait'// }
Object notation for hierarchical states:
// ...const waitState = lightMachine.transition({ red: 'walk' }, 'PED_TIMER').value;// => { red: 'wait' }lightMachine.transition(waitState, 'PED_TIMER').value;// => { red: 'stop' }lightMachine.transition({ red: 'stop' }, 'TIMER').value;// => 'green'
Parallel State Machines

const wordMachine = createMachine({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;// {// bold: 'on',// italics: 'off',// underline: 'off',// list: 'none'// }const nextState = wordMachine.transition({bold: 'off',italics: 'off',underline: 'on',list: 'bullets'},'TOGGLE_ITALICS').value;// {// bold: 'off',// italics: 'on',// underline: 'on',// list: 'bullets'// }
History States

const paymentMachine = createMachine({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');// => State {// value: { method: 'check' },// history: State { ... }// }const reviewState = paymentMachine.transition(checkState, 'NEXT');// => State {// value: 'review',// history: State { ... }// }const previousState = paymentMachine.transition(reviewState, 'PREVIOUS').value;// => { method: 'check' }
Sponsors
Huge thanks to the following companies for sponsoring xstate. You can sponsor further xstate development on OpenCollective.



