Describe what the application actually knows
Loading means a result is not ready, empty means a successful result contains no matching records, and error means the application could not obtain a trustworthy result. These are different claims. A blank table with No results is misleading when the request failed. Model the alternatives before designing their visual treatment so the interface remains honest when conditions are less than ideal.
Check HTTP outcomes explicitly
A fetch promise can resolve with an HTTP error response, so inspect response.ok or the relevant status before treating the body as successful data. Parsing can also fail independently of the status code. Keep transport, response interpretation and application validation distinguishable in the code. That separation makes it possible to show a useful explanation without guessing which stage went wrong.
Follow a project search example
For a query that returns no matches, keep the query visible and offer to clear filters or try another term. For a request that fails, explain that projects could not be loaded and provide a retry. When older valid results remain on screen, label their relationship to the pending request clearly. A spinner should not make outdated rows appear to answer the newest query.
Preserve input and prevent conflicting actions
A failed save should normally retain the draft that took time to enter. Disable or coordinate actions that would create duplicate requests, while leaving safe navigation and correction available. A retry should use a clearly defined current input snapshot. If the original operation may already have reached the server, retry behavior may require idempotency support rather than another identical button click.
Make diagnostics useful without exposing internals
A visitor needs a concise explanation and next step, not a raw stack trace or a complete server response. Developers may need a request identifier and the failing stage. Avoid logging passwords, tokens or full personal records. Keep cancellation separate from failure when the user simply changed a query or left the screen intentionally.
Verify each state as a real scenario
Exercise a delayed success, an empty response, a non-success status, malformed data and an unavailable network. Retry after failure and change input while an earlier request is pending. Check keyboard access and announcements for changed feedback. The screen should explain whether the person should wait, correct something, retry or change the query, rather than displaying one generic placeholder for every outcome.
Further reading
Put the idea to work.
Explore free browser tools for images, text and developer workflows.