# Identifying State Nodes
These XState v4 docs are no longer maintained
XState v5 is out now! Read more about XState v5 (opens new window) and check out the XState v5 docs (opens new window).
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 = createMachine({
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: { target: '#light.yellow' }
}
},
yellow: {
on: {
TIMER: { target: 'red' }
}
},
red: {
on: {
TIMER: { target: 'green' }
}
}
}
});
# Relative Targets
Child state nodes can be targeted relative to their parent by specifying a dot ('.'
) followed by their key:
const optionsMachine = createMachine({
id: 'options',
initial: 'first',
states: {
first: {},
second: {},
third: {}
},
on: {
SELECT_FIRST: { target: '.first' }, // resolves to 'options.first'
SELECT_SECOND: { target: '.second' }, // 'options.second'
SELECT_THIRD: { target: '.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 = createMachine({
id: 'light',
initial: 'green',
states: {
green: {
// custom identifier
id: 'greenLight',
on: {
// target state node by its ID
TIMER: { target: '#yellowLight' }
}
},
yellow: {
id: 'yellowLight',
on: {
TIMER: { target: '#redLight' }
}
},
red: {
id: 'redLight',
on: {
// relative targets will still work
TIMER: { target: 'green' }
}
}
}
});
Notes:
- IDs are always recommended for the root state node.
- 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]'
.
# Quick Reference
Default, automatically generated ID:
const lightMachine = createMachine({
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: { target: '#light.yellow' }, // target default ID
ANOTHER_EVENT: { target: '#custom-id' } // target custom ID
}