Skip to content
Version: XState v4

Options

Statecharts require that a machine is separated into two parts. The first part is the machine’s config. The config describes how the machine behaves — its states, events and transitions.

The second part is a machine’s options — implementation details that expand the machine’s capabilities.

Options can:

  • Make decisions based on checks, such as an if/else statement
  • Make changes to the machine’s surrounding environment
  • Subscribe to changes from the machine’s outside environment

In XState, the separation is divided between:

TermDescription
ConfigWhat the machine does
OptionsHow the machine does it

Below is an example where we describe in our config that when the machine first starts, it 'says hello', using the sayHello action.

const helloMachine = createMachine({
/**
* Below is an 'action' — we’ll
* learn more about actions later
*/
entry: ['sayHello'],
});

As a visualization, the config is readable. But the machine doesn’t do anything yet.

Options let us pass an implementation for the sayHello action.

const helloMachine = createMachine(
{
entry: ['sayHello'],
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
},
},
);

The separation between “what your code does” and “how your code does it” is powerful because it allows you to understand its purpose without requiring you to read through the implementation details.

Option types

There are four types of options you can pass to your statechart.

Guards

Guards allow you to check something before you proceed, enabling you to implement if/else logic in XState.

Below is an example of a guard:

import { createMachine } from 'xstate';

let iAmHappyAndIKnowIt = true;

const machine = createMachine(
{
initial: 'notClappingHands',
states: {
notClappingHands: {
on: {
HEAR_MUSIC: {
/**
* Name the guard…
*/
cond: 'ifYoureHappyAndYouKnowIt',
target: 'clappingHands',
},
},
},
clappingHands: {},
},
},
{
guards: {
/**
* …then implement the guard.
*/
ifYoureHappyAndYouKnowIt: () => {
return iAmHappyAndIKnowIt;
},
},
},
);

In the example above, the guard is activated when the machine is in the notClappingHands state and reaches the HEAR_MUSIC event. If the ifYoureHappyAndYouKnowIt guard is true, the machine will go to the clappingHands state.

Actions

Actions allow you to perform simple actions, such as assigning to a variable or calling synchronous actions:

import { createMachine } from 'xstate';

const machine = createMachine(
{
entry: ['sayHello'],
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
},
},
);

In the example above, sayHello will be called when the machine is started.

Actors

Actors are entities that have their own state and can send and receive events. Actors are useful for processes like:

  • Subscribing to a websocket/DOM listener for updates
  • Invoking a promise and waiting for it to resolve
  • Uploading a file

We’ll revisit actors in more depth later. Take a fast track to learn more about actors.

Delays

Delays are used in XState to represent timers and intervals. We’ll revisit delays in more depth later. Take a fast track to learn more about delays.

Options API

You can specify machine options in several places. Firstly, you can set options inside the machine itself:

import { createMachine } from 'xstate';

const machine = createMachine(
{
// Set config here
},
{
// Set options here:
actions: {},
// `actors` in v5
services: {},
guards: {},
delays: {},
},
);

Or, you can specify options later with a .withConfig call:

import { createMachine } from 'xstate';

const machine = createMachine({});

// ---cut---

machine.withConfig({
actions: {},
// `actors` in v5
services: {},
guards: {},
delays: {},
});

Summary

Options are how you make your machine do things. They allow machines to keep control of the config and enable you to pass in options later.