UX & Frontend
Empty, Loading & Error State Audit
- Best for
- Apps with data-dependent views, API integrations, async UI, or user-generated content. Live twins: prompts 437 (empty states) and 438 (loading states) verify these in the running app.
- Use when
- Before launch, after adding new data views, or when users report blank screens or confusion
You are a UI/frontend engineer conducting a comprehensive async states audit. Your goal is to catalog every data-dependent view and verify that users see helpful, well-designed feedback in every possible state — loading, loaded, empty, partially loaded, and error. This audit covers both the engineering implementation (are all states handled in code?) and the design quality (are the states well-crafted and consistent?).
This is the umbrella audit. For deeper passes on a single state class, see: prompt 326 (Error Message Catalog) and 436 (browser-MCP version), prompt 437 (Empty State Catalog via Browser MCP), prompt 438 (Loading State Catalog via Browser MCP). Run 71 first for orientation, then drill into the worst state class via the specialized prompts.
Methodology: Find all async data fetches: React Query hooks, SWR hooks, Apollo queries, useEffect+fetch patterns, Suspense boundaries, and error boundaries. For each data-dependent component, check all five states: loading, loaded, empty, error, and partial. Then evaluate the design quality of each state. Start with the views users hit most often. The most common findings are missing empty states, silent error handling, and loading states that don't match the content layout.
What good looks like: Every async component has a skeleton or spinner during loading, sized and shaped to match actual content. Empty states include a clear explanation and a CTA ("No projects yet -- create your first one"). Error states tell the user what happened and offer a retry action. States are scoped to the component, not a single global loading indicator for the entire app. Design is consistent across the app.
Component Identification Checklist
- Components using
useQuery,useSWR,useQuery(Apollo) - Components with
useEffectthat sets state from a fetch - Components that receive async data as props from a parent data-fetching component
- List views, dashboards, data tables, and detail pages that display server data
- Modal dialogs that fetch data on open
- Suspense boundaries with fallback components
- Error boundaries with fallback UI
Empty States
Engineering:
- For each dynamic data view: does the component explicitly check for an empty result and render a distinct empty state?
- Is the empty result check correct? (e.g.,
data.length === 0vs.!data— the latter is falsy for empty arrays in some frameworks)
Design quality:
- Do empty states explain WHY it's empty and offer a CTA to fix it?
- Are first-time empty states ("You haven't created any projects yet") differentiated from filtered-to-zero states ("No results for 'xyz'")?
- Is the empty state visually distinct from the loading state (not just a white box)?
- Are empty state illustrations or icons used, or is it just text?
- Is the empty state context-sensitive to the user's current action?
Loading States
Engineering:
- Does every async component render a loading indicator during the initial fetch?
- Is the loading state scoped to the affected component, not the whole page?
- Does the component avoid layout shift when loading transitions to loaded?
- On background refetches: is a stale version shown (preferred) or is the loading state re-shown?
- If the app uses Suspense + Suspense boundaries with proper fallbacks, do the fallbacks match?
Design quality:
- Are skeleton screens used for content areas, with shapes matching actual content layout?
- Is there a minimum display time (~300ms) to avoid flash-of-skeleton?
- Do full-page loaders block interaction? Can users navigate away during slow loads?
- Are loading indicators the right type for the context? (Skeleton for content, spinner for actions, progress bar for uploads)
Error States
Engineering:
- Does every async component render an error state when the fetch fails?
- Does the error state offer a retry action that actually re-triggers the fetch?
- Are network errors distinguished from server errors in the code path?
- Is error state visually distinct from the empty state and the loaded state?
- Is there an error boundary wrapping the component to catch render errors?
Design quality:
- Are error messages user-friendly with plain language (not raw error codes or exception messages)?
- Are different error types handled differently: offline, server error, permission denied, not found, timeout?
- Do forms show inline validation, preserve input after failure, and use specific messages?
- Is the error message tone appropriate (not blaming the user)?
Partial Loading
- Are page sections loaded independently so users can interact with loaded areas?
- If a subsequent request fails, does existing data persist?
- Are optimistic updates used where appropriate?
- Single item failure in a list — does it break the whole list?
Pagination & Infinite Scroll States
- Does the first page load show a loading skeleton?
- Does loading the next page show a localized indicator, not a full-page spinner?
- Does reaching the last page show a clear "You've reached the end" message?
- Does a failed page load show a retry for just that page, not a full reset?
State Transitions
- Loading to content: no layout shift?
- Loading to empty: clear that loading finished (not just blank screen)?
- Loading to error: uses timeouts, not 30-second waits?
- Error retry shows loading state?
Edge Cases
- Slow connection: does the loading state remain stable and not flicker?
- Partial data: if some items succeed and some fail, are partial results shown with an error banner?
- Cached stale data: while background refetching, is the stale data clearly shown (not hidden behind a spinner)?
- Component unmounted before fetch resolves: is the state update suppressed to prevent memory leaks?
- Broken images, third-party widget failure
- Session expiry mid-action, deleted/archived resource access
- Deployment chunk loading errors (code-split bundles)
Calibration
- Severity context: A primary dashboard or list page that renders blank during loading or shows nothing on an empty result is High — it's the first thing users see and creates confusion about whether the product works. Missing empty state on the main dashboard is critical. A secondary stats widget with no loading indicator is Low. Missing loading state on a monthly settings page is Low. Weight by view frequency.
- Confidence ratings: Mark each finding as Confirmed (visibly missing or broken — verified the component has no loading/empty/error branch in its render logic), Likely (exists but inadequate — data fetching found but JSX doesn't show evidence of the state being handled), or Speculative (may fail under untested conditions — state may be handled by a parent component or error boundary).
- Anti-hallucination guard: Global error boundaries catch unhandled render errors, but they are not a substitute for component-level empty and error states. However, if the app uses Suspense + Suspense boundaries with proper fallbacks, do not flag individual component loading states as missing — check the Suspense boundary instead. If a view handles all five states well, say so. A clean audit is a valid outcome.
Output Format
Start with a 3-5 line executive summary: how many async components/views were audited, how many handle all states, the single most impactful missing state, and the overall async state handling posture.
- Component Inventory — Table with columns: Component | Data Source | Loading State | Empty State | Error State | Status (Complete/Partial/Missing)
- Missing States — For each gap: file:line, which state is missing (loading/empty/error/partial/transition), current behavior, user impact, and recommended fix with specific copy, UI treatment, and code pattern
- Design Inconsistency — Any components handling the same data source with different state patterns, or inconsistent skeleton/spinner/error styling across the app. Identify the standard pattern to align to.
- Positive Findings — Views and components with well-implemented state handling that can serve as examples for the rest of the codebase