# Hierarchical state nodes

In statecharts, states can be nested within other states. These nested states are called compound states. To learn more, read the compound states section in our introduction to statecharts.

# API

The following example is a traffic light machine with nested states:

const pedestrianStates = {
  initial: 'walk',
  states: {
    walk: {
      on: {
        PED_COUNTDOWN: { target: 'wait' }
      }
    },
    wait: {
      on: {
        PED_COUNTDOWN: { target: 'stop' }
      }
    },
    stop: {},
    blinking: {}
  }
};

const lightMachine = createMachine({
  key: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: { target: 'yellow' }
      }
    },
    yellow: {
      on: {
        TIMER: { target: 'red' }
      }
    },
    red: {
      on: {
        TIMER: { target: 'green' }
      },
      ...pedestrianStates
    }
  },
  on: {
    POWER_OUTAGE: { target: '.red.blinking' },
    POWER_RESTORED: { target: '.red' }
  }
});

The 'green' and 'yellow' states are simple states - they have no child states. In contrast, the 'red' state is a compound state since it is composed of substates (the pedestrianStates).

# Initial states

When a compound state is entered, its initial state is immediately entered as well. In the following traffic light machine example:

  • the 'red' state is entered
  • since 'red' has an initial state of 'walk', the { red: 'walk' } state is ultimately entered.
console.log(lightMachine.transition('yellow', { type: 'TIMER' }).value);
// => {
//   red: 'walk'
// }

# Events

When a simple state does not handle an event, that event is propagated up to its parent state to be handled. In the following traffic light machine example:

  • the { red: 'stop' } state does not handle the 'TIMER' event
  • the 'TIMER' event is sent to the 'red' parent state, which handles the event.
console.log(lightMachine.transition({ red: 'stop' }, { type: 'TIMER' }).value);
// => 'green'

If neither a state nor any of its ancestor (parent) states handle an event, no transition happens. In strict mode (specified in the machine configuration), this will throw an error.

console.log(lightMachine.transition('green', { type: 'UNKNOWN' }).value);
// => 'green'