State machines can sound intimidating at first — all those diagrams and boxes and arrows. But at the heart of it, they’re built on three incredibly simple ideas: states, events, and transitions. If you've ever handled a button click or shown a loading spinner, you've already worked with them. This week, we're going to demystify how these pieces fit together and why they can make your UI logic feel like it finally makes sense.
✨ Intro: The Foundation of Every State Machine
In the last issue, we looked at why state machines are a better way to model UI logic. This week, we’re breaking down the three concepts that power every state machine:
States – the different modes your UI can be in
Events – the things that happen to trigger change
Transitions – how you move from one state to another
Once you understand these, even the most complex flows start to feel… obvious.
🧠 What Is a State?
A state is just a label for a condition your UI is in.
🔁 Example: A toggle switch has two states: active and inactive. A form might have: idle, validating, submitting, success, error.
You define them up front — and your component can only be in one of them at a time.
⚡ What Is an Event?
An event is something that happens — usually triggered by the user or the system.
👇 Examples:
A click → TOGGLE
A form submission → SUBMIT
An API call fails → FAILURE
Events don’t do anything on their own — they ask the machine to change.
🔄 What Is a Transition?
A transition is how the machine changes from one state to another in response to an event.
Think of it as: "When I'm in [this state] and [this event] happens, move to [that state]."
In XState, it looks like this:
createMachine({
initial: 'idle',
states: {
idle: {
on: { SUBMIT: 'submitting' }
},
submitting: {
on: {
SUCCESS: 'success',
FAILURE: 'error'
}
},
success: {},
error: {}
}
});🧪 Why This Structure Is Powerful
Because you define states and transitions explicitly, you avoid:
Ambiguous conditions
Invalid combinations (e.g. isLoading && isError)
“Where am I in the flow?” type bugs
The machine won’t allow transitions that aren’t defined. That’s safety by design.
Visualize It
Here’s that form state machine as a diagram:
Diagrams like this aren’t just pretty — they’re living documentation of how your app behaves.
🧠 Pro Tip: Events Are the API of Your Component
Instead of exposing a bunch of props or handlers, you can think of your UI machine as exposing one clean interface:
send({ type: 'SUBMIT' });That’s it. Consumers of your component don’t care about your internal logic — they just send events and get predictable behavior.
Coming Up Next: Modeling UI with XState
In the next issue, we’ll get hands-on: ✅ Setting up XState in a React project ✅ Using useMachine ✅ Connecting state to your UI
We’ll build a real machine and hook it into a real component.
💡 Try This
Pick a small UI in your app (a toggle, button, form, etc) and answer:
What are the possible states?
What events can happen?
How do you transition from one to another?
Try modeling it on paper — or in Stately.ai
Reply to this with your flow — I’d love to feature a few in future issues!
Until next time,
Horacio
Do you like what you are reading?. Subscribe to receive updates.
Unsubscribe anytime