Skip to content
Version: XState v5

Parallel states

In statecharts, a parallel state is a state that has multiple child states (also known as regions) that are all active at the same time. This is different from a parent state, where only one child state is active at a time.

Parallel states have the following characteristics:

  • Entering a parallel state will also simultaneously enter all of its regions.
  • Exiting a parallel state will also simultaneously exit all of its regions.
  • An event received in a parallel state is simultaneously received & handled by all of its regions.

Here is a music player example with a parallel state consisting of two regions, one for handling playing the track and one for handling the volume:

import { createMachine, assign } from 'xstate';

const playerMachine = createMachine({
id: 'player',
type: 'parallel',
states: {
track: {
initial: 'paused',
states: {
paused: {
on: { PLAY: 'playing' },
},
playing: {
on: { STOP: 'paused' },
},
},
},
volume: {
initial: 'normal',
states: {
normal: {
on: { MUTE: 'muted' },
},
muted: {
on: { UNMUTE: 'normal' },
},
},
},
},
});

Parallel state value

The state value of a parallel state is an object with the state values of each of its regions.

const playerActor = createActor(playerMachine);
playerActor.start();

console.log(playerActor.getSnapshot().value);
// logs the object:
// {
// track: 'paused',
// volume: 'normal'
// }

Parallel onDone transition

When all regions of a parallel state have reached their final states, the onDone transition of the parallel state is taken.

In this example, the onDone transition of the parallel state is taken when both regions have reached their final states; that is, when 'grindingBeans' reaches the 'grindingBeans.beansGround' state and 'boilingWater' reaches the 'boilingWater.waterBoiled' state.

import { createMachine } from "xstate";

export const machine = createMachine({
id: "coffee",
initial: "preparing",
states: {
preparing: {
states: {
grindBeans: {
initial: "grindingBeans",
states: {
grindingBeans: {
on: {
BEANS_GROUND: {
target: "beansGround",
},
},
},
beansGround: {
type: "final",
},
},
},
boilWater: {
initial: "boilingWater",
states: {
boilingWater: {
on: {
WATER_BOILED: {
target: "waterBoiled",
},
},
},
waterBoiled: {
type: "final",
},
},
},
},
type: "parallel",
onDone: {
target: "makingCoffee",
},
},
makingCoffee: {},
},
});

Modeling

Coming soon

  • Avoid transitions between regions
  • Used for separation of concerns that may affect each other (i.e. synchronization)
  • If completely separate, prefer invoke instead

Cheatsheet

Create a parallel state

import { createMachine } from "xstate";

const machine = createMachine({
// ...
states: {
type: 'parallel',
states: {
one: {/* ... */},
two: {/* ... */},
three: {/* ... */}
},
onDone: {
// Taken when all regions have reached their final states
}
}
});