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 - 🔬 
@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/vue- Vue composition functions and utilities for using XState in Vue applications - ✅ 
@xstate/test- Model-Based-Testing utilities (using XState) for testing any software - 🔍 
@xstate/inspect- Inspection utilities for XState 
Get started by forking one of these templates on CodeSandbox:
- XState Template - no framework
 - XState + TypeScript Template - no framework
 - XState + React Template
 - XState + React + TypeScript Template
 - XState + Vue Template
 - XState + Vue 3 Template
 - XState + Svelte Template
 
npm install xstateimport { 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 state
const toggleService = interpret(toggleMachine)
  .onTransition((state) => console.log(state.value))
  .start();
// => 'inactive'
toggleService.send('TOGGLE');
// => 'active'
toggleService.send('TOGGLE');
// => 'inactive'📉 See the visualization on xstate.js.org/viz
import { createMachine, interpret, assign } from 'xstate';
const fetchMachine = createMachine({
  id: 'Dog API',
  initial: 'idle',
  context: {
    dog: null
  },
  states: {
    idle: {
      on: {
        FETCH: 'loading'
      }
    },
    loading: {
      invoke: {
        id: 'fetchDog',
        src: (context, event) =>
          fetch('https://dog.ceo/api/breeds/image/random').then((data) =>
            data.json()
          ),
        onDone: {
          target: 'resolved',
          actions: assign({
            dog: (_, event) => event.data
          })
        },
        onError: 'rejected'
      },
      on: {
        CANCEL: 'idle'
      }
    },
    resolved: {
      type: 'final'
    },
    rejected: {
      on: {
        FETCH: 'loading'
      }
    }
  }
});
const dogService = interpret(fetchMachine)
  .onTransition((state) => console.log(state.value))
  .start();
dogService.send('FETCH');- Visualizer
 - Why?
 - Finite State Machines
 - Hierarchical (Nested) State Machines
 - Parallel State Machines
 - History States
 - Sponsors
 
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:
- 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
 
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;
// => 'yellow'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;
// => {
//   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'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;
// {
//   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'
// }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');
// => 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' }Huge thanks to the following companies for sponsoring xstate. You can sponsor further xstate development on OpenCollective.