xstate
    TypeScript icon, indicating that this package has built-in type declarations

    4.25.0 • Public • Published


    XState
    JavaScript state machines and statecharts

    npm version Statecharts gitter chat

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

    📖 Read the documentation 📑 Adheres to the SCXML specification.

    Packages

    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'

    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 { 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

    Hierarchical Light Machine

    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

    Parallel state machine

    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

    Machine with history state

    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.

    Install

    npm i xstate

    DownloadsWeekly Downloads

    707,367

    Version

    4.25.0

    License

    MIT

    Unpacked Size

    732 kB

    Total Files

    121

    Last publish

    Collaborators

    • davidkpiano