Hosted ondailyplanet.iovia theHypermedia Protocol

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:

Button

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