Need help with xstate?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

davidkpiano
13.9K Stars 598 Forks MIT License 3.0K Commits 129 Opened issues

Description

State machines and statecharts for the modern web.

Services available

!
?

Need anything else?

Contributors list


XState
JavaScript state machines and statecharts

npm version Statecharts gitter chat

Black lives matter. Support the Equal Justice Initiative. ✊🏽✊🏾✊🏿

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

📖 Read the documentation 📑 Adheres to the SCXML specification.

Packages

Templates

Get started by forking one of these templates on CodeSandbox:

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 state const toggleService = interpret(toggleMachine) .onTransition((state) => console.log(state.value)) .start(); // => 'inactive'

toggleService.send('TOGGLE'); // => 'active'

toggleService.send('TOGGLE'); // => 'inactive'

Promise example

📉 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

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

xstate visualizer

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:

Finite State Machines

Light Machine

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'

Hierarchical (Nested) State Machines

Hierarchical Light Machine

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'

Parallel State Machines

Parallel state machine

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' // }

History States

Machine with history state

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' }

Sponsors

Huge thanks to the following companies for sponsoring

xstate
. You can sponsor further
xstate
development on OpenCollective.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.