Problem
While panels load, blank areas can look like finished results with no data.
Solution
Reserve the space each panel will occupy and show a clear loading state. Replace it without moving content that people are already reading.
Keep loading distinct from an empty result or error. Use a text or status cue as well as any animation, and respect reduced-motion preferences.
Detect failed or stalled requests instead of leaving placeholders indefinitely. During refreshes, keep useful existing data visible with its age and refresh status.
Use when
Loading takes long enough to notice, especially when panels finish at different times.
Don’t use when
The response is genuinely fast. A skeleton that flashes for 80ms is visual noise and makes a fast page feel busy. Delay showing it by a couple of hundred milliseconds so quick responses never trigger it at all.
Trade-offs
Placeholders need to match the final layout and can drift as it changes. Many animations add distraction and rendering work. Loading feedback helps explain a wait but does not replace fixing slow queries.
Checklist
- Is the skeleton the same size and position as the content it replaces?
- Does the layout stay still when real data arrives?
- Is loading distinguishable from empty, and from error, at a glance?
- Is there a delay before showing it, so fast responses never flash?
- Is there a timeout, and what state does it fall into?
- Do panels load independently, and does the page look coherent half-loaded?
- Does anything animate, and does it respect prefers-reduced-motion?
- On a wallboard, what does a viewer twenty feet away see during load?
- Does a refresh clear existing data to skeletons, or update in place?
- Would showing the previous values, marked stale, serve better than a skeleton?
Compare
Grafana loads panels independently with a per-panel spinner, so a dashboard settles progressively and a slow panel is visibly the slow one rather than holding up the page. Netdata sidesteps the pattern by streaming: charts begin drawing as data arrives rather than waiting for a complete response, so there is little gap to fill. Sentry uses shaped skeletons that match its list rows closely enough that the transition to real content is nearly invisible, which is the pattern done well on a predictable layout. Honeycomb shows query progress rather than a placeholder, which suits a product where a query can legitimately take long enough that Nielsen’s ten-second rule applies and an estimate is owed.
Related
Empty state shows a completed request with no results. Error and stale state handles failed or outdated results. Dense small-multiple layout makes independent loading especially visible.
Freshness indicator supports showing old data during a refresh. Panel grid keeps the layout stable.