Skip to content
Version: XState v5

Final states

A final state is a state that represents the completion or successful termination of a machine. It is defined by the type: 'final' property on a state node:

import { createMachine, interpret } from 'xstate';

const feedbackMachine = createMachine({
initial: 'prompt',
states: {
prompt: {
/* ... */
},
thanks: {
/* ... */
},
closed: {
type: 'final',
},
// ...
},
on: {
'feedback.close': {
target: '.closed',
},
},
});

When a machine reaches the final state, it can no longer receive any events, and anything running inside it is canceled and cleaned up. The box with a surrounding border icon represents the final state.

A machine can have multiple final states or no final states.

  • A state machine can have zero or more final states. Some machines may run indefinitely and not need to terminate.
  • Final states can have output data, which is sent to the parent machine when the machine terminates.
  • When a machine reaches a top-level final state, it terminates.
  • Final states cannot have transitions

Using final states in Stately Studio

In the video player above, Stopped is the final child state in the Opened state. When the video player is Stopped, the video player moves to its Closed state.

Make a state a final state

First, select the state you want to set as the final state.

Using the quick actions menu

  1. Right-click the state to bring up the quick actions menu.
  2. Choose Final from the Type options.

Using the State details panel

  1. Select the state you want to set as the final state.
  2. Open the State details panel from the right tool menu.
  3. Choose Final from the Type dropdown menu.

Top-level final states

A top-level final state is a final state that is a direct child state of the machine. When the machine reaches a top-level final state, the machine will terminate. When a machine terminates, it can no longer receive events nor transition.

Child final states

When a child final state of a compound state is reached, that compound state is considered "done". The onDone transition of that compound state is taken.

Final states in parallel states

When all regions of a parallel state are "done", the parallel state is considered "done". The onDone transition of the parallel state is taken.

In this example, the preparation state is a parallel state with two regions: beans and water. When both regions are done, the preparation state is done, and the brewing state is entered.

import { createMachine, interpret } from 'xstate';

const coffeeMachine = createMachine({
initial: 'preparation',
states: {
preparation: {
type: 'parallel',
states: {
beans: {
initial: 'grinding',
states: {
grinding: {
on: {
grindingComplete: 'ground',
},
},
ground: {
type: 'final',
},
},
},
water: {
initial: 'heating',
states: {
heating: {
always: {
guard: 'waterBoiling',
target: 'heated',
},
},
heated: {
type: 'final',
},
},
},
},
onDone: 'brewing',
},
brewing: {},
},
});

Output

When a machine reaches its top-level final state, it can produce output data. You can specify this output data in the .output property of the top-level final state:

import { createMachine, interpret } from 'xstate';

const currencyMachine = createMachine({
// ...
states: {
converting: {
// ...
},
converted: {
type: 'final',
output: ({ context }) => ({
amount: context.amount,
currency: context.currency,
}),
},
},
});

const currencyActor = interpret(currencyMachine, {
input: {
amount: 10,
fromCurrency: 'USD',
toCurrency: 'EUR',
},
});

currencyActor.onDone(() => {
console.log(currencyActor.getSnapshot().output);
// logs e.g. { amount: 12, currency: 'EUR' }
});
  • .output can also be a static value

TypeScript

Coming soon

Cheatsheet

Coming soon