Github url

xstate

by davidkpiano

davidkpiano /xstate

State machines and statecharts for the modern web.

12.2K Stars 491 Forks Last release: 5 days ago (@xstate/[email protected]) MIT License 2.7K Commits 112 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

[ XState
JavaScript state machines and statecharts

](https://xstate.js.org)

npm versionStatecharts 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: '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!

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.