Free guideEditorial review in progress; your agent sees whether each guide's current version is reviewed. What “reviewed” means

Every screen needs a state matrix: loading, empty, error, offline, partial, first-run

A principle and checklist for designing all states of each app screen before styling the happy path, with the minimum content for each state and a state model that makes impossible combinations unrepresentable.

Discipline
Apps
Type
Principle
Platforms
Cross-platform, iOS, Android
Version
1.1.1 · 2026-09-26

Overview

What: A per-screen matrix of states that must be designed and implemented: first-run, loading, loaded (normal), empty, no-results, partial (some data failed), error, offline/degraded, and permission-denied where relevant.

Why: The happy path is a minority of real sessions. Apple's HIG says never make people stare at nothing while content loads and never show an alert at launch for problems you can show inline; NN/g stresses that blank screens make users unsure whether the system is working. The Motif blueprint requires loading, empty, permission-denied, offline/degraded and recoverable-error behaviour on every screen.

Use when: specifying or reviewing any screen.

Not optional for list, detail, form and settings screens.

Implementation

  1. Write the matrix first (columns = states, rows = screens). Minimum content per state:
StateMust show
First-runwhat this area is for + primary create action
Loadingskeleton of the real layout (or nothing if < ~300 ms)
Emptywhy empty + how to fill it
No resultsquery/filters echoed + broadening actions
Partialloaded data + inline notice for the failed part + retry
Errorplain cause + what's safe + Retry / alternative
Offlinecached data + "Offline — changes will sync" or "Needs connection"
Permission deniedwhat's unavailable + how to enable
  1. Model state as a discriminated union, not booleans:
type ListState =
  | { kind: 'loading' }
  | { kind: 'ready'; items: Item[]; stale?: boolean }
  | { kind: 'empty' }
  | { kind: 'error'; error: AppError; items?: Item[] };

This makes "loading and error at once" impossible and forces each screen to render every kind.

  1. Local-only apps: there is still loading (DB open/migration), empty, error (disk full, migration failure) and no-results — but no offline state. Don't invent network messaging for local data.
  2. Preserve context in error states: keep previously loaded content visible with an inline banner instead of replacing it with a full-screen error.
  3. Build a state gallery: a dev-only route (e.g. app/_dev/states.tsx) or Storybook that renders each screen in each state with fixture data, used for screenshots and review.
  4. Copy: every state has a headline, one sentence of explanation, and at most one primary action.

Rubric wiring and the five required states (added in 1.1.0). The design gate requires loading, empty, error, offline and success designed on every key screen; any one undesigned on a shipped key screen is hard-fail HF-A8. Score anchors: 3/5 = all five designed with skeletons matching final layout; 4/5 = first-use empty states offer the first action, errors are recoverable with retry, offline shows cached content and queues actions; 5/5 = state design carries the product's voice and trust posture (weighted success confirmation, honest degradation). Two functional-truth rules also count as state defects: a declared count rendered short without a truncation affordance (HF-A12), and a visualisation that is not proportional or not legible at render size (caps state completeness at 2) — see app-functional-truth-rulings. Record the per-screen state design in the note's "State design" field.

Verification

  • Each screen has a completed matrix; unsupported states are marked N/A with a reason.
  • A state gallery renders every screen × state; screenshots exist in light and dark.
  • Forcing failures (airplane mode, corrupt DB fixture, denied permission) produces the designed states, not blank screens or raw error text.
  • No state shows a network message in a local-only app.
  • Screen readers announce state changes (e.g. "No results", "Couldn't load").
  • The note's state field lists all five states per key screen; counts and charts satisfy the functional-truth rules.

Sources:

Limitations

  • The matrix grows multiplicatively with multi-pane layouts; prioritise states by frequency and harm.
  • Some states merge in simple apps (first-run ≈ empty); merge deliberately, don't skip.
  • A dev-only state gallery must be excluded from production builds.
  • Partial and first-run states from this matrix are refinements of the five required states, not substitutes for them.
  • Values verified 2026-09-26: all 1 numeric values in this item were checked (1 against published design guidelines) and confirmed; no corrections were needed.