The Loading State
What the interface says while it waits, which shapes how long the wait feels.
The problem it solves
Work takes time and the interface has to account for it. A blank screen reads as broken, and a spinner with no end in sight reads as stuck.
Same wait, different treatment
Perceived duration is not actual duration. A wait with visible progress, a named task, and something to look at feels shorter than an identical wait with a rotating circle. That is the whole leverage of this pattern, and it costs almost nothing to use.
Pick the treatment by duration
- Under 100ms
- Show nothing. A flash of a spinner at this length is worse than no feedback at all, because it registers as a glitch.
- 100ms to 1s
- Optimistic update or a subtle in-place state. The button goes quiet, the row dims. No overlay.
- 1s to 10s
- A skeleton that matches the shape of what is coming, or a determinate progress bar. The layout should not jump when the content arrives.
- Over 10s
- Named steps and an estimate, plus a way to leave. Tell them they can close the tab and you will email when it is done.
Skeletons beat spinners for content because they set an expectation about the shape of the result. They stop working when they lie: a three-line skeleton followed by a twelve-line article, or a skeleton left up for thirty seconds, both feel worse than an honest message.
Waiting copy that feels endless
- Loading...
- Please wait
- Processing your request
- This may take a while
Waiting copy that passes the time
- Fetching your last 90 days of transactions
- Step 2 of 4: matching bank records
- Importing 1,240 of 3,500 contacts. About 40 seconds left
- This usually takes 3 to 5 minutes. You can close this tab and we will email you when the report is ready
Optimistic updates are the strongest move available when the operation nearly always succeeds. Show the result immediately, send the request in the background, and reconcile if it fails. The wait disappears entirely. The cost is that the failure path has to be designed properly, with a clear rollback and a message that explains what came undone.
Worked example
A hypothetical progress rewrite
An export screen shows a spinner for roughly forty seconds. The team replaces it with four named steps and a count. The job takes exactly as long. The team expects fewer people to reload the page mid-export, which is worth checking, because a reload restarts the job and makes the real wait twice as long.
When it fits
- The operation reliably takes long enough that a person would notice silence.
- You can report genuine progress, steps, or a defensible estimate.
- The page layout is known in advance, so a skeleton can match it without shifting.
- Very long jobs can be handed to a background queue with a notification at the end.
When it backfires
- A spinner appears for a request that resolves in 80 milliseconds, which reads as a flicker or a fault.
- A skeleton is shown for an unbounded wait, so it stops being a preview and becomes a lie.
- The progress bar is fake and pauses at 99 percent, which people recognise and distrust.
- Optimistic updates ship without a rollback story, so failures silently discard the user's action.
Products using it
Facebook
Popularised content skeletons that mirror the shape of a post while it loads.
Slack
Posts a message optimistically and marks it as pending if the send has not confirmed, rather than blocking the input.
Vercel
Streams named build steps with elapsed time during deployment instead of showing one indeterminate bar.
The psychology under it
The takeaway
Match the treatment to the duration, name the work in progress, and never fake a progress bar.
Finished the teardown? Bank it and the day counts toward your run.
