Skip to main content
On this pageMessages as Events

Messages

Messages as Events

Messages describe what happened, not what to do. Name them as verb-first, past-tense events where the prefix acts as a category marker: Clicked* for button presses, Updated* for input changes, Succeeded*/Failed* for command results that can meaningfully fail, Completed* for fire-and-forget Command acknowledgments, Got* for child module results via the OutMessage pattern. For example, ClickedFormSubmit and RemovedCartItem rather than imperative commands like SubmitForm or RemoveFromCart.

Good Message Names

  • ClickedAddToCart
  • ChangedSearchInput
  • ReceivedUserData

Avoid These

  • SetCartItems
  • UpdateSearchText
  • MutateUserState

The update function decides how to handle a Message. The Message itself is just a fact about what occurred.

Every Message Carries Meaning

Never use a generic NoOp Message. Every Message should describe what happened, even for fire-and-forget Commands where the update function is a no-op. For example, when a focus Command completes, use CompletedButtonFocus. When scroll is locked, use CompletedScrollLock. When an internal navigation finishes, use CompletedInternalNavigation.

Notice that this is the opposite of how you name Commands. lockScroll reads as an instruction because it is one — Commands are imperative, verb-first: lockScroll, focusButton, showModal. The resulting Message flips the order because it’s a fact, not an instruction: CompletedScrollLock, CompletedButtonFocus, CompletedDialogShow. Object-first naming also puts the distinguishing word earlier — instead of scanning past CompletedFocus* three times to find CompletedFocusButton as distinct from CompletedFocusItems, you see CompletedButtonFocus and CompletedItemsFocus where the second word immediately tells you what was affected.

This turns the DevTools timeline from a wall of identical NoOp entries into a readable narrative: OpenedCompletedItemsFocus, CompletedScrollLock, CompletedInertSetup. Every line tells you what happened in your application.

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson