Identifying State Nodes

🚀 Quick Reference

By default, a state node's id is its delimited full path. You can use this default id to specify a state node:

const lightMachine = Machine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      // default ID: 'light.green'
      on: {
        // You can target state nodes by their default ID.
        // This is the same as TIMER: 'yellow'
        TIMER: '#light.yellow'
      }
    },
    yellow: { on: { TIMER: 'red' } },
    red: { on: { TIMER: 'green' } }
  }
});

Relative Targets

Child state nodes can be targeted relative to their parent by specifying a dot ('.') followed by their key:










 
 
 



const optionsMachine = Machine({
  id: 'options',
  initial: 'first',
  states: {
    first: {},
    second: {},
    third: {}
  },
  on: {
    SELECT_FIRST: '.first', // resolves to 'options.first'
    SELECT_SECOND: '.second', // 'options.second'
    SELECT_THIRD: '.third' // 'options.third'
  }
});

By default, relative targets are internal transitions, which means the parent state will not exit and reenter. You can make relative targets external transitions by specifying internal: false:




 




// ...
on: {
  SELECT_FIRST: {
    target: '.first',
    internal: false // external transition, will exit/reenter parent state node
  }
}

Custom IDs

State nodes can be targeted via unique identifiers, instead of by relative identifiers. This can simplify the creation of complex statecharts.

To specify an ID for a state node, provide a unique string identifier as its id property, e.g., id: 'greenLight'.

To target a state node by its ID, prepend the '#' symbol to its string ID, e.g., TIMER: '#greenLight'.

const lightMachine = Machine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      // custom identifier
      id: 'greenLight',
      on: {
        // target state node by its ID
        TIMER: '#yellowLight'
      }
    },
    yellow: {
      id: 'yellowLight',
      on: {
        TIMER: '#redLight'
      }
    },
    red: {
      id: 'redLight',
      on: {
        // relative targets will still work
        TIMER: 'green'
      }
    }
  }
});

Notes:

  • IDs are always recommended for the root state node.
  • IDs are useful for SCXML compatibility, and conversion to/from SCXML will make use of IDs extensively.
  • Make sure that all IDs are unique in order to prevent naming conflicts. This is naturally enforced by the automatically generated IDs.

WARNING

Do not mix custom identifiers with relative identifiers. For example, if the red state node above has a custom "redLight" ID and a child walking state node, e.g.:

// ...
red: {
  id: 'redLight',
  initial: 'walking',
  states: {
    // ID still resolves to 'light.red.walking'
    walking: {/* ... */},
    // ...
  }
}
// ...

Then you cannot target the 'walking' state via '#redLight.walking', because its ID is resolved to '#light.red.walking'. A target that starts with '#' will always refer to the exact match for the '#[state node ID]'.

Avoiding strings

If you don't want to use strings for identifying states, object getters can be used to directly reference the target state:

const lightMachine = Machine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        // Use a getter to directly reference the target state node:
        get TIMER() {
          return lightMachine.states.yellow;
        }
      }
    },
    yellow: {
      on: {
        get TIMER() {
          return lightMachine.states.red;
        }
      }
    },
    red: {
      on: {
        TIMER: {
          // Also works with target as a getter
          get target() {
            return lightMachine.states.green;
          }
        }
      }
    }
  }
});

WARNING

The getter must be a pure function that always returns the same value, which is a StateNode instance. Using getters to reference state nodes is completely optional, and useful if you want to avoid strings or have stricter typings. This getter will only be called once.

SCXML

IDs correspond to the definition of IDs in the SCXML spec:

{
  green: {
    id: 'lightGreen';
  }
}
<state id="lightGreen">
  <!-- ... -->
</state>

Quick Reference

Default, automatically generated ID:

const lightMachine = Machine({
  id: 'light',
  initial: 'green',
  states: {
    // ID: "light.green"
    green: {
      /* ... */
    },
    // ID: "light.yellow"
    yellow: {
      /* ... */
    },
    // ID: "light.red"
    red: {
      /* ... */
    }
  }
});

Custom ID

// ...
states: {
  active: {
    id: 'custom-active', // can be any unique string
    // ...
  }
}

Targeting state node by ID:

// ...
on: {
  EVENT: '#light.yellow', // target default ID
  ANOTHER_EVENT: '#custom-id' // target custom ID
}