Skip to content

Surfaces, Flows, and States

The units of product-design work. When this handbook (or a ProductFeeling agent command) says “audit this surface” or “review this flow,” these are the definitions in play.

  • A surface is anything a user encounters and reads meaning from: a screen, a component, a modal, an empty list, an error toast, a push notification, an email, a CLI message, a loading spinner. If the user can see it and form a feeling about it, it is a surface.
  • A flow is an ordered sequence of surfaces through which a user pursues one job: signup, first export, checkout, cancellation. Flows have entrances (where intent arrives from), exits (success, abandonment, error), and a feeling trajectory—not just a conversion rate.
  • A state is one of the conditions a single surface can be in. Every surface has at least five: ideal (the screenshot state), empty (nothing to show yet), loading (waiting on the system), partial (some data, awkward amounts), and error (something failed). This is Scott Hurff’s “UI stack,” and it is the most engineer-actionable idea in product design.
  • A moment is a point in a flow with outsized emotional weight: first value, a permission ask, a payment, a failure, a goodbye. Moments are where the Peak–End Rule concentrates its effect.

Design tools and code reviews both default to the ideal state, but users spend most of their emotional life in the other four:

flowchart TB
  subgraph surface [One surface — five states]
    Empty[Empty]
    Loading[Loading]
    Partial[Partial]
    Error[Error]
    Ideal[Ideal — the screenshot]
  end
  Empty --> Ideal
  Loading --> Ideal
  Partial --> Ideal
  Error --> Ideal
  Loading --> Error

A new user meets the empty state before the ideal one; a user on a slow connection meets loading; a user with three items instead of thirty meets partial; every user eventually meets error. Products feel broken not because the ideal state is wrong but because the non-ideal states were never designed—they were left to whatever the framework renders when data is missing.

The five states are not equal in emotional stakes:

  • Empty is a first impression and a fork: it either teaches the next step or communicates “nothing for you here” (Empty States).
  • Loading is a promise about time; unexplained waits read as failure long before they time out (Loading Feedback, Perceived Effort Delay).
  • Partial is where layouts break and comparisons embarrass (“you have 1 friends”). It is the state real usage lives in longest.
  • Error is a trust event, not an edge case (Graceful Recovery).
  • Ideal earns its polish only when the other four hold (Aesthetic–Usability Effect).

Flows add a second dimension: state transitions across surfaces. The feeling of a flow is dominated by its worst transition—an unexplained jump, a lost draft between steps, a back button that discards work. Mapping a flow means mapping intent at entry, state at each surface, and what each exit (including abandonment) leaves the user with—including Graceful Exit at the largest scale.

Three TTPs handle acknowledgement of change and waiting. Agents reviewing PRs should classify before applying a card:

Signal TTP Meaning
State changed Micro Interactions The action registered; cause and effect are clear
Work pending Loading Feedback The system is working; wait is honest and proportionate
Work is staged Perceived Effort Delay Real work is shown as it happens—never fake delay to look busy
flowchart LR
  Risk[Risky action] --> FS[Fail Safe — prevent or undo]
  FS -->|mistake blocked| Safe[User continues]
  FS -->|system still fails| GR[Graceful Recovery]
  Outage[Outage or error state] --> GR
  GR --> Repair[Explain, preserve work, repair]

Fail Safe prevents costly mistakes before they land (confirmations, undo, safe defaults). Graceful Recovery is what happens after failure is real (honest errors, preserved work, repair). Do not rewrite Fail Safe as a recovery card, or Recovery as another confirmation dialog.

There is no dedicated TTP for partial data—treat it as a first-class design problem under Empty States + layout QA: pluralisation, sparse tables, and “awkward counts” that make the product feel broken even when the API succeeded.

  • Every component you ship has all five states whether or not anyone designed them. Before merging UI code, ask: what renders when the array is empty, the promise is pending, the request 500s, and the data is one item instead of fifty?
  • States are enumerable, which makes them testable: Storybook stories, fixture data, and snapshot tests per state turn “design review” into a checklist. An agent auditing a surface should enumerate the five states and report which are unhandled.
  • Flow review is a state-machine review: draw the surfaces as nodes and the user’s transitions as edges, then check every edge for preserved work, preserved context, and an honest exit. Dead ends (states with no forward edge) are bugs even when no exception is thrown.
  • Loading and error states are usually decided in the data layer (timeouts, retries, optimistic updates, cache staleness), not in the view. If the API contract has no story for “slow” and “failed,” the surface cannot have one either.