Two apps, same load time, different feel
A blank white screen for 800ms feels slower than a skeleton layout for 800ms, even though the clock says the same thing. The gap between actual and perceived performance is where most of the "feels slow" feedback lives — and it's cheaper to close than shaving real milliseconds off a query.
Perceived performance isn't a trick that hides slowness. It's an honest signal that something is happening, given early enough that the wait stops feeling like uncertainty and starts feeling like progress.
Techniques that change how a wait feels
Skeletons over spinners
A spinner tells the user to wait and gives no other information. A skeleton shows the shape of what's coming, so the transition to real content feels continuous rather than a jump-cut.
Optimistic UI for reversible actions
Toggling a checkbox or archiving an item can update the UI immediately and reconcile with the server after. Reserve this for actions that are safe to roll back if the request fails.
Stage the load, don't gate it
Render the shell and cheap data first, stream in the expensive parts (charts, aggregates) as they arrive. Waiting for everything before showing anything makes every page as slow as its slowest widget.
Respond to the click before the request
A button press should show a pressed state and disable itself within a frame, not wait for the network to confirm the click registered.
Debounce the wait, not the feedback
Debouncing a search request is correct; debouncing the loading indicator so it never shows for fast responses is what makes fast searches feel instant instead of merely quick.
Know when optimistic UI is the wrong call
Payments, irreversible deletes, anything with real-world consequences should wait for confirmation. Optimism there just moves the bad news later, and makes it worse.
The failure path is part of the perceived-performance budget
Optimistic UI only holds up if the rollback path is designed with the same care as the happy path. An optimistic update that silently reverts, with no explanation, is worse than no optimism at all — it erodes trust in every future "instant" interaction, because the user learns the UI sometimes lies.
The takeaway
Skeleton screens, staged loading and optimistic updates close the gap between how fast an app is and how fast it feels — but only when the failure and rollback paths get the same design attention as the happy path. Perceived performance is a budget, not a trick.
Let's talk about your product