Skip to content
1 of 3 project slots open
Writing
Design · part 2 of 54 min read

Every screen has five states

Empty, loading, partial, error and ideal. Most apps only design the last one.

Meer Habib

Senior Mobile Engineer · Chittagong

Most screens are designed once, in their best moment: full of good data, loaded, working. Users spend a surprising amount of time in the other moments. Every screen that shows data has at least five states, and a product feels finished when all five were designed on purpose.

Add first
empty
loading
partial
Retry
error
ideal
Fig. 1The same screen, five ways. Most apps only design the last one.

1. Empty

There's nothing here yet. This is often the first thing a new user sees, which makes it one of the most important screens in the app.

Empty comes in three kinds, and they need different words:

  • First use: "No notes yet." Show what will live here and one clear action to create the first one.
  • Cleared: the user finished everything. Celebrate a little; don't nag.
  • No results: a search or filter found nothing. Say what was searched, and offer to clear the filter.

A blank white screen is never the right empty state.

2. Loading

If you know the shape of what's coming, show it: a skeleton of the list, the rows, the image boxes. The layout doesn't jump when data arrives, and the wait feels shorter.

If you don't know the shape, a small spinner is fine. Two details matter more than the spinner itself:

  • Don't flash it. If data usually arrives within a few hundred milliseconds, wait that long before showing anything.
  • Keep what you had. When refreshing, leave the old content on screen and update it in place. Replacing a full list with a spinner every time someone pulls to refresh is the most common loading mistake I see.

3. Partial

Some data, not a lot. One note, when the design assumed ten. A profile with no photo. A list showing cached items while you're offline.

Partial is where a product can teach. One item plus a gentle hint about the next thing to try is more useful than an empty space where the rest of the list would be.

4. Error

Something went wrong. A good error state answers three questions in plain words:

  1. What happened? "Couldn't save your note."
  2. Is my stuff safe? "It's still here, on your phone."
  3. What can I do? Retry, check the connection, or contact support.

Keep everything the user typed. Tell different failures apart, because "you're offline", "the server had a problem" and "you don't have access" need different actions. Never show a raw error code as the only message.

5. Ideal

The screen you designed first. It still deserves one more check: too much. Very long names, a number with nine digits, a list with ten thousand items, a translated label twice as long as the English one. Design for the overflow before a user finds it.

In code: one value, not four flags

If the screen tracks isLoading, isError, isEmpty and data separately, it can end up in impossible combinations, like loading and errored at once. Model it as one value instead:

type Screen<T> =
  | { status: "loading" }
  | { status: "error"; error: string; retry: () => void }
  | { status: "empty"; reason: "first-use" | "cleared" | "no-results" }
  | { status: "ready"; items: T[] };

Now the component has to handle every state, and the type checker tells you when you forgot one. There's more on this in component patterns that scale.

The checklist

  • Design all five before building any of them.
  • Three kinds of empty, three different messages.
  • Skeletons for known layouts; never flash a spinner.
  • Refresh in place.
  • Errors say what happened, that data is safe, and what to do.
  • Test the overflow.

Previous: mobile UI standards, measured. Next: design systems, from tokens to screens.

Building something like this?

Booking new projects for Q4. Replies within 24h.