Performance & Feedback

Loading States and Skeletons

Loading States and Skeletons

The seconds between a tap and a response decide whether users trust your product. Match the right pattern to the wait, the scope, and the reversibility of the action.

what would you do?

Your import flow takes 15-40 seconds depending on file size. Right now it shows a single spinner with no other feedback. What should you build instead?

Support tickets show users refreshing the page mid-import, assuming it's frozen, and re-uploading the same file. The wait is well past the point where a spinner reads as trustworthy, and duration varies enough that you can't hardcode a countdown.

A

Keep the spinner but add a bigger, more noticeable animation

B

Switch to determinate progress with step labels ("Validating rows... Step 2 of 4") and a way to background the task

C

Replace the spinner with a full skeleton screen of the results table

D

Add a static "Please don't close this window" warning above the spinner

The Problem

Users don't experience "performance" as a backend metric. They experience it as a moment of uncertainty: did my tap register, is this broken, should I click again? NN/G's timing thresholds still map cleanly to product work: around 0.1 seconds feels instantaneous, 1 second preserves flow, and 10 seconds is roughly where attention starts drifting [1].

That uncertainty has measurable commercial consequences. Baymard's mobile research found that slow response times on mobile sites were common, severe, and caused abandonment during testing, and Reforge notes that load time can be a major driver of bounce rate on acquisition-sensitive surfaces [2].

There's a subtler failure too: a product can look ready before it's actually usable. When buttons are visible but not yet interactive, people assume the page is broken and leave, or stack clicks and create duplicate actions. Loading states are the most routine way products either pass or fail the basic test of answering a user's action clearly [3].

The Three-Question Framework

  1. How long will this probably take?

  2. What surface is loading: a small control, a module, or a whole page?

  3. Can the UI safely assume success and reconcile later?

The practical rule is to respond immediately, then escalate the amount of feedback only as needed. For sub-second waits, a pressed state or optimistic response is usually enough. For short isolated waits, use a spinner. For full-screen content loads, use a skeleton that reveals structure. For long or process-heavy waits, switch to determinate progress with steps and time estimates [4].

Skeletons are not "better spinners." NN/G recommends them specifically for full-page loads, not for uploads, conversions, or other process tasks. Their value is that they preview layout, reduce uncertainty, and create the impression of gradual progress [5].

Determinate versus indeterminate is the foundational split. Apple's HIG frames it simply: use determinate indicators when you can estimate duration, and indeterminate ones when you can't. Material and Android converge on the same logic in their own component language [6].

Optimistic UI removes the wait entirely for simple, reversible, high-success actions, responding before the network round trip completes and rolling back on failure. Smashing Magazine's constraint is that failures should surface within about 2 seconds so the interface doesn't effectively lie about success [7].

Real Product Case Studies

Full Skeleton Screen on App Launch
Previewing the home screen's layout before restaurant data resolves

Uber Eats

The design decision

On launch, the home screen renders its full structure immediately, search bar, category circles, and stacked restaurant cards, all filled with gray placeholder blocks in the exact size and position the real content will take. Nothing waits behind a spinner; the whole page appears at once, just unresolved.

Why it works

Because location, delivery address, and nearby restaurants all depend on a slower personalization query, showing the finished layout in outline form immediately tells users the app is alive and exactly what kind of screen they're on. NN/G's research on skeleton screens found this reduces the abruptness of a blank-to-dense transition and creates the impression of a shorter wait [5].

Descriptive Indeterminate State for AI Processing
Naming an unpredictable process instead of leaving it silent

Step-Based Progress for a Personalization Flow
Breaking a multi-second setup process into visible, sequential stages

Pattern Fit by Use Case


Use Case

Recommended Pattern

Avoid

Feed or home timeline

Skeleton screen, progressive reveal

Full-screen spinner

Analytics dashboard

Section-level skeletons per card

One global spinner blocking everything

Modal opened from current page

Small spinner inside the modal body

Full-page skeleton for a small overlay

Form submit under a few seconds

Button loading state, disable repeat submit

Static "Please wait" warning text

Upload, import, export, conversion

Determinate progress, steps, or queue estimate

Skeleton screens

Like, save, wishlist, archive

Optimistic UI with rollback

Spinner on a near-certain, low-risk action


Mistakes That Kill Success

avoid this

Skeletons for Process Tasks

Using a skeleton for an upload, conversion, or payment check. NN/G is explicit that skeletons are for full-page loads, not process work, they imply "page structure is arriving" when what's actually happening is "a job is running" [5].

The fix
Swap to a determinate progress bar, step indicator, or queue estimate for anything that's genuinely a process, not a page render.

avoid this

A Page That Looks Ready Before It Is

Buttons and content render before handlers are actually wired up. Users tap, nothing happens, they assume the page is broken and either leave or stack duplicate clicks [3].

The fix
Keep controls visibly disabled until they're truly interactive, or use progressive reveal that makes the hydration state explicit.

avoid this

Static Text on Long Waits

A bare "Loading..." label or an infinite spinner past 10-20 seconds gives no signal that anything is actually progressing, so users start refreshing or resubmitting[4].

The fix
Move to determinate progress past 10 seconds, and refresh the message once a wait passes 20 seconds so it still reads as alive.

Metrics That Matter

Largest Contentful Paint (LCP)
Time until the main content element is visible. Target: under 2.5 seconds at the 75th percentile, segmented by mobile and desktop.

Why it matters: LCP is the true-performance baseline that any loading pattern is layered on top of, it measures loading, not perceived polish [9].

Interaction to Next Paint (INP)
How quickly the product reacts once a user taps or clicks. Target: 200 milliseconds or less.

Duplicate-Click Rate
Percentage of submissions where a user pressed the same control more than once. Formula: duplicate clicks ÷ total submissions × 100

The Strategic Opportunity

3x

How much longer people are willing to wait when a moving progress indicator is shown, compared with no indicator at all. Good feedback doesn't fake speed, it keeps people engaged long enough for real value to arrive.

Feedback Extends Patience
NN/G cites evidence that moving progress bars increase satisfaction and can make people willing to wait roughly three times longer than when no indicator is shown at all [4].

Slow Response Times Cause Abandonment
Baymard's mobile research found slow response times on mobile sites were common, severe, and directly caused abandonment during usability testing [2].

Small Speed Gains Move Conversion
NN/G notes that shaving even 0.1 second from response time can improve conversion, performance is interpreted as competence[1].

Prototyping Loading States Early Pays Off
Reforge frames speed as a driver of bounce rate and recommends prototyping error, empty, and loading states early, they're easy to miss in static design files [10].

Resources Worth Your Time

Loading Pattern Guidance

Research

NN/G: Skeleton Screens 101

When skeletons help, when they don't, and the three skeleton types to avoid or use

Platform

Apple HIG: Loading

The determinate versus indeterminate split that underlies every platform's guidance

Research

NN/G: Progress Indicators

Timing thresholds and why moving feedback extends how long people will wait

Platform

Material Design: Loading Indicator

Component-level guidance for short loads under five seconds

Research

NN/G: Skeleton Screens 101

When skeletons help, when they don't, and the three skeleton types to avoid or use

Research

NN/G: Progress Indicators

Timing thresholds and why moving feedback extends how long people will wait

Platform

Apple HIG: Loading

The determinate versus indeterminate split that underlies every platform's guidance

Platform

Material Design: Loading Indicator

Component-level guidance for short loads under five seconds

Optimistic UI & Perceived Performance

Patterns

Simon Hearne: Optimistic UI Patterns

Real examples and the sub-100ms rule for decoupling feedback from the network

Strategy

Reforge Blog

Why loading, error, and empty states belong in early prototypes, not late polish

Critique

Smashing: True Lies of Optimistic UI

Where optimistic UI breaks down and how to reconcile failures honestly

Operating Model

Lenny's Newsletter

How teams like Notion treat invisible states once designs leave Figma for the browser

Patterns

Simon Hearne: Optimistic UI Patterns

Real examples and the sub-100ms rule for decoupling feedback from the network

Critique

Smashing: True Lies of Optimistic UI

Where optimistic UI breaks down and how to reconcile failures honestly

Strategy

Reforge Blog

Why loading, error, and empty states belong in early prototypes, not late polish

Operating Model

Lenny's Newsletter

How teams like Notion treat invisible states once designs leave Figma for the browser

Keep the insights coming

Keep the insights coming

Weekly product decisions, real examples, and proven patterns from products that actually work.

Weekly product decisions, real examples, and proven patterns from products that actually work.

Weekly product decisions, real examples, and proven patterns from products that actually work.