Documentation Index
Fetch the complete documentation index at: https://mintlify.com/statelyai/xstate/llms.txt
Use this file to discover all available pages before exploring further.
The or() function creates a higher-order guard that evaluates to true if any of the guards passed to it evaluate to true.
Signature
function or<
TContext extends MachineContext,
TExpressionEvent extends EventObject,
TArg extends unknown[]
>(
guards: readonly [
...{
[K in keyof TArg]: SingleGuardArg<
TContext,
TExpressionEvent,
unknown,
TArg[K]
>;
}
]
): GuardPredicate<
TContext,
TExpressionEvent,
unknown,
NormalizeGuardArgArray<DoNotInfer<TArg>>
>;
Parameters
An array of guards to evaluate. Each guard can be:
- A named guard string (e.g.,
'isValid')
- A guard object with
type and optional params
- An inline guard function
Returns
A guard that returns true if any provided guard evaluates to true, otherwise false.
Usage
Basic Example
import { setup, or } from 'xstate';
const machine = setup({
guards: {
isAdmin: ({ context }) => context.role === 'admin',
isModerator: ({ context }) => context.role === 'moderator'
}
}).createMachine({
context: {
role: 'user' as 'user' | 'admin' | 'moderator'
},
on: {
DELETE: {
guard: or(['isAdmin', 'isModerator']),
actions: () => {
console.log('User has deletion privileges');
}
}
}
});
Mixing Named and Inline Guards
import { setup, or } from 'xstate';
const machine = setup({
guards: {
hasSubscription: ({ context }) => context.subscription !== null
}
}).createMachine({
context: {
subscription: null as string | null,
isFreeTrial: false,
isPromoUser: false
},
on: {
ACCESS_PREMIUM: {
guard: or([
'hasSubscription',
({ context }) => context.isFreeTrial,
({ context }) => context.isPromoUser
]),
target: 'premiumContent'
}
}
});
Fallback Validation
import { setup, or } from 'xstate';
const machine = setup({
guards: {
hasValidEmail: ({ context }) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(context.email),
hasValidPhone: ({ context }) => /^\d{10}$/.test(context.phone)
}
}).createMachine({
context: {
email: '',
phone: ''
},
on: {
SUBMIT: {
guard: or(['hasValidEmail', 'hasValidPhone']),
target: 'submitted',
description: 'Requires at least one valid contact method'
},
INVALID: {
guard: ({ context }) => !context.email && !context.phone,
target: 'error'
}
}
});
With Guard Parameters
import { setup, or } from 'xstate';
const machine = setup({
guards: {
hasMinItems: ({ context }, params: { min: number }) => {
return context.items.length >= params.min;
},
isSpecialUser: ({ context }) => context.userType === 'special'
}
}).createMachine({
context: {
items: [] as string[],
userType: 'regular' as 'regular' | 'special'
},
on: {
CHECKOUT: {
guard: or([
{ type: 'hasMinItems', params: { min: 1 } },
'isSpecialUser'
]),
target: 'checkout'
}
}
});
Permission Checking
import { setup, or } from 'xstate';
const machine = setup({
guards: {
hasEditPermission: ({ context }) => context.permissions.includes('edit'),
hasAdminPermission: ({ context }) => context.permissions.includes('admin'),
isOwner: ({ context, event }) => context.userId === event.resourceOwnerId
}
}).createMachine({
context: {
userId: '',
permissions: [] as string[]
},
on: {
EDIT_RESOURCE: {
guard: or([
'hasEditPermission',
'hasAdminPermission',
'isOwner'
]),
actions: 'editResource'
}
}
});
Nested Composition
import { setup, or, and } from 'xstate';
const machine = setup({
guards: {
isPremiumUser: ({ context }) => context.tier === 'premium',
hasCredits: ({ context }) => context.credits > 0,
isInTrialPeriod: ({ context }) => context.trialDaysLeft > 0
}
}).createMachine({
on: {
USE_FEATURE: {
guard: or([
'isPremiumUser',
and(['hasCredits', 'isInTrialPeriod'])
]),
actions: 'useFeature'
}
}
});
Behavior
- Short-circuit evaluation: Once a guard returns
true, remaining guards are not evaluated
- Empty array: An empty array is treated as
false (no guards passed)
- Order matters: Guards are evaluated left-to-right until one returns
true
- Performance: Place most likely conditions first for optimal performance
Type Safety
The or() function maintains type safety across all guards:
type Context = { role: string; credits: number };
type Event = { type: 'ACCESS'; resourceId: string };
const machine = setup({
types: {} as {
context: Context;
events: Event;
},
guards: {
isAdmin: ({ context }) => context.role === 'admin',
hasCredits: ({ context }) => context.credits > 0
}
}).createMachine({
on: {
ACCESS: {
guard: or([
'isAdmin',
'hasCredits',
({ context, event }) => event.resourceId === 'free-resource'
])
}
}
});
See Also