Thinking

Loading States Are Not One Component

Design Systems·May 20, 2026·5 min read

Every design system has a spinner. Most have added a skeleton screen component at some point. Some have a progress bar. What almost none of them have is a clear decision rule for which one to use when — which means developers reach for whichever is easiest to implement and designers ship whatever ships fastest.

The result is the most common loading state failure: a skeleton screen on a two-field form submission, or a spinner on a page that takes eight seconds to load, or nothing at all on a surface that took 400ms to respond and now looks broken. Loading states are not one component. They’re a family of patterns, each designed for a specific combination of duration, content type, and user expectation. Getting it wrong doesn’t just look bad — it erodes the sense that the product is working correctly.


Spinners— for short, bounded waits (1–10 seconds) and single actions. A spinner signals “the system received your action and is working.” The classic use case is a button state after submission: the user clicked, the request is in flight, the spinner confirms the click registered.

Spinners are best for waits of 2–10 seconds. For delays over 10 seconds, progress bars are strongly recommended because they give users a sense of the state of the system and how much longer they have to wait [1]. Two failure modes to avoid: a full-page spinner for loads over a few seconds (no sense of progress, time feels longer than it is), and a spinner that appears for under 300ms (it flickers before the user can process it, creating confusion rather than reassurance). Delay spinner appearance by 200–300ms for actions that might resolve quickly.

Skeleton screens— for content loads with known structure (1–10 seconds). A skeleton screen previews the layout before the content arrives. Its job is to reduce perceived wait time by giving users something real to process — the structure of what’s coming — rather than an abstract animation.

Studies show users perceive sites with skeleton screens as 30% faster than identical sites with spinners, despite identical actual loading times [3]. The mechanism is psychological: the user is building a mental model of the page rather than watching a loop. Active waiting feels shorter than passive waiting.

Skeleton screens fail when the skeleton doesn’t match what actually loads. If the placeholder shows three cards and twelve rows arrive, the layout shift undermines the trust the skeleton was supposed to build. They work best when loading container-based components: tiles, structured lists, grids, data tables, card components [5]. Do not use skeleton screens for form submissions or processing actions — the skeleton implies content is coming, not a confirmation state or redirect.

Progress bars— for long or measurable operations (10+ seconds, or known progress). A progress bar makes one promise: I can tell you how much is done and how much is left. This promise creates an obligation. Don’t stop progress at 99% [4]. A bar that freezes just before completion destroys the trust the entire pattern was trying to build.

Progress bars belong on uploads, exports, file processing, multi-step batch operations — anything where duration is estimable and the user needs to decide whether to wait or come back. For truly indeterminate processes, a progress bar is worse than a spinner because it implies a precision it can’t deliver.

Optimistic UI— for actions with high success probability. This is often left out of loading state documentation because it’s technically not a loading state at all — it’s the removal of one. Optimistic UI assumes the action will succeed, updates the interface immediately, and handles errors only if they occur.

The right contexts: low-stakes reversible actions (liking a post, marking a task complete, toggling a setting). The wrong contexts: irreversible or high-stakes actions (submitting a payment, deleting data, sending an email). In those cases, a brief loading state is not friction — it’s appropriate confirmation that something real is happening.

The four loading state patterns — and when each belongs
PatternDurationBest for
Spinner2–10 secondsSingle actions, button states after submission — bounded wait with no layout to preview
Skeleton screen1–10 secondsContent loads with predictable structure — cards, lists, grids, data tables
Progress bar10+ secondsMeasurable operations — uploads, exports, batch processing, multi-stage flows
Optimistic UI< 300ms (assumed)Low-stakes reversible actions — likes, toggles, task completion, status changes
A spinner communicates activity. A skeleton communicates structure. A progress bar communicates measurable progress. Optimistic UI removes the wait entirely. Each solves a different problem.

Before reaching for a component, two questions determine the answer. Does the user need to see layout structure while they wait? If yes, use a skeleton screen for loads under 10 seconds. Can the system estimate duration or progress? If yes, use a progress bar. If no and the wait is short, use a spinner. If no and the wait is long, use a spinner with contextual copy (“This may take a few minutes”).

One override: if the action will resolve in under 300ms with high confidence, show nothing. A flash of loading UI for an instant action creates confusion, not reassurance.

The four patterns — what each looks like in use
Spinner
Saving changes…
2–10s · single action · no layout to preview
Skeleton screen
1–10s · known layout · content load
Progress bar
report_q4.csv
73% · 2.1 MB of 2.9 MB
10s+ · measurable operation
Optimistic UI
Saved to favouritesUndo
<300ms · reversible action
Start from the condition, not the component. Duration, content type, and action stakes determine the pattern — not which component is in the design system.

References

  1. Nielsen Norman Group (2024). Skeleton Screens 101. nngroup.com
  2. Nielsen Norman Group. Skeleton Screens vs. Progress Bars vs. Spinners (Video). nngroup.com
  3. UI Deploy (2025). Skeleton Screens vs. Spinners: Optimizing Perceived Performance. ui-deploy.com
  4. Pencil & Paper (2022). UX Design Patterns for Loading. pencilandpaper.io
  5. LogRocket (2025). Skeleton Loading Screen Design. blog.logrocket.com
Loading state is not a design afterthought. ⏳ It's the moment the product earns trust — or quietly loses it. 🔒 Loading state is not a design afterthought. ⏳ It's the moment the product earns trust — or quietly loses it. 🔒 Loading state is not a design afterthought. ⏳ It's the moment the product earns trust — or quietly loses it. 🔒 Loading state is not a design afterthought. ⏳ It's the moment the product earns trust — or quietly loses it. 🔒