States
Define state nodes and read machine snapshots.
XState v6 is in alpha
State nodes are values in a machine's states object.
const machine = createMachine({
initial: 'idle',
states: {
idle: {},
active: {},
complete: { type: 'final' }
}
});State node types
- Atomic states have no children.
- Compound states have children and one active child at a time.
- Parallel states activate every child region at once.
- Final states complete their parent and can produce output.
- History states remember the previously active child.
- Choice states resolve to a target instead of resting.
See machine configuration for every property a state node accepts.
State snapshots
actor.getSnapshot() returns a machine snapshot: an immutable description of the machine at one point in time.
| Member | Type | Description |
|---|---|---|
value | string or nested object | The active state value. |
context | object | Current context. |
status | 'active' | 'done' | 'error' | 'stopped' | Snapshot status. |
children | Record<string, ActorRef> | Invoked and spawned child actors, keyed by id. |
output | output type or undefined | Machine output; only set when status is 'done'. |
error | unknown | Only set when status is 'error'. |
tags | Set<string> | Tags of all active state nodes. |
nodes | StateNode[] | Active state nodes represented by value. |
historyValue | object | Remembered values for history states. |
timers | Record<string, LogicalTimer> | Pending delayed and timeout timers. |
machine | StateMachine | The machine that produced this snapshot. |
| Method | Returns | Description |
|---|---|---|
matches(partialValue) | boolean | Whether the state value matches a partial value. Narrows the snapshot type. |
can(event) | boolean | Whether the event would take a non-forbidden transition. |
hasTag(tag) | boolean | Whether any active state node has the tag. |
getMeta() | Record<stateId, meta> | Metadata of active state nodes. |
getInputs() | Record<stateId, input> | State input of active state nodes. |
toJSON() | object | Serializable form, with tags as an array. See serialization. |
Matching state values
matches(...) accepts a partial state value. A parent match succeeds no matter which child is active.
snapshot.matches('active');
snapshot.matches({ checkout: 'payment' });
snapshot.matches({ checkout: { payment: 'authorizing' } });For parallel states, pass only the regions to check. Unlisted regions are ignored.
// value: { player: { playback: 'playing', volume: 'muted' } }
snapshot.matches({ player: { playback: 'playing' } }); // truematches(...) narrows the snapshot type, so context that only exists in that state becomes available inside the branch.
Checking events
can(...) answers whether sending an event right now would select a transition that is not forbidden, even if that transition has no actions and does not change the state value.
snapshot.can({ type: 'submit' });Because v6 conditions live inside transition functions, can(...) calls those functions to see whether they return a transition. It does not execute their effects: enqueued actions, raised events and sent events are discarded. Keep transition functions free of side effects outside enq(...) so that can(...) stays safe to call during rendering.
A checkout button can be disabled with can({ type: 'submit' }) instead of duplicating the machine's rules.
Tags
Tags label states that share a meaning. Declare them per state node, and their type with schemas.tags.
const machine = createMachine({
schemas: { tags: z.enum(['busy', 'error']) },
initial: 'idle',
states: {
idle: {},
uploading: { tags: ['busy'] },
processing: { tags: ['busy'] }
}
});
snapshot.hasTag('busy');
snapshot.tags; // Set { 'busy' }uploading and processing can both render the same spinner without the view knowing either state name.
Metadata
meta attaches static data to a state node. getMeta() returns the metadata of every active state node, keyed by state node id.
const machine = createMachine({
id: 'upload',
schemas: { meta: z.object({ label: z.string() }) },
initial: 'selecting',
states: {
selecting: { meta: { label: 'Choose a file' } },
uploading: { meta: { label: 'Uploading…' } }
}
});
snapshot.getMeta(); // { 'upload.uploading': { label: 'Uploading…' } }State nodes without meta are omitted. Metadata must match schemas.meta.
TypeScript
Literal state keys are inferred from the machine configuration, so matches(...) rejects unknown values. Use SnapshotFrom<typeof machine> for the snapshot type.
import type { SnapshotFrom } from 'xstate';
type UploadSnapshot = SnapshotFrom<typeof machine>;States cheatsheet
snapshot.value;
snapshot.context;
snapshot.status;
snapshot.children;
snapshot.output;
snapshot.error;
snapshot.matches('idle');
snapshot.matches({ loading: 'user' });
snapshot.can({ type: 'submit' });
snapshot.hasTag('busy');
snapshot.getMeta();
snapshot.getInputs();
snapshot.toJSON();