Skip to content
Version: XState v5

Delayed (after) transitions

Delayed transitions are transitions that are triggered after a set amount of time. Delayed transitions are useful for building timeouts and intervals into your application logic. If another event occurs before the end of the timer, the transition doesn’t complete.

Delayed transitions are defined on the after property of a state node, either as a number (measured in milliseconds) or as a string that references a delay defined in the delays setup object.

import { createMachine } from 'xstate';

const pushTheButtonGame = createMachine({
initial: 'waitingForButtonPush',
states: {
waitingForButtonPush: {
after: {
5000: {
target: 'timedOut',
actions: 'logThatYouGotTimedOut',
},
},
on: {
PUSH_BUTTON: {
actions: 'logSuccess',
target: 'success',
},
},
},
success: {},
timedOut: {},
},
});

Delays

You can define delays in a few ways: inlined, referenced, and as an expression.

Inlined delays

You can define an inlined delay by specifying the delay time (in milliseconds) directly:

const machine = createMachine({
initial: 'idle',
states: {
idle: {
after: {
1000: { target: 'nextState' },
},
},
nextState: {},
},
});

This will transition to the nextState state after 1000ms.

Referenced delays

You can also define referenced delays by specifying a string delay key, and providing the actual delay time separately.

For example:

import { setup } from 'xstate';

const machine = setup({
delays: {
timeout: 1000,
},
}).createMachine({
initial: 'idle',
states: {
idle: {
after: {
timeout: { target: 'nextState' },
},
},
nextState: {},
},
});

Dynamic delays

Delays can also be dynamically defined as a function that returns the delay time in milliseconds:

import { setup } from 'xstate';

const machine = setup({
types: {
context: {} as {
attempts: number;
},
},
delays: {
timeout: ({ context }) => {
return context.attempts * 1000;
},
},
}).createMachine({
initial: 'attempting',
states: {
attempting: {
after: {
timeout: {
actions: assign({ attempts: ({ context }) => context.attempts + 1 }),
target: 'attempting',
},
},
},
// ...
},
});

Lifecycle

Delayed transition timers are canceled when the state is exited.

Testing

  • Simulated clock

Delayed transitions and TypeScript

You can strongly type the delays of your machine by setting up the the delays in the setup() function:

import { setup } from 'xstate';

const machine = setup({
delays: {
shortTimeout: 1000,
longTimeout: 5000,
eventually: 10_000,
},
}).createMachine({
after: {
shortTimeout: {
/* ... */
},
},
});

Delayed transitions cheatsheet

Use our XState delayed transitions cheatsheet below to get started quickly.

createMachine({
after: {
DELAY: {
/* ... */
},
},
}).provide({
delays: {
DELAY: 1000, // or expression
},
});