Empty, error, and loading states
The three screens every view needs besides the happy one: nothing yet, still fetching, and something broke.
See it
What it is
Every view that fetches something has four states, not one: loading, empty, error, and populated. Designers mock the populated one, engineers ship the populated one, and users hit the other three on day one. Naming them as a set is the whole trick, because it turns 'handle edge cases' into a checklist you can actually finish.
Each state has a job. Loading holds the layout still (a skeleton that matches the real shape beats a centered spinner). Empty teaches: say why it is empty and put the one action that fills it right there, which is why a good empty state doubles as onboarding. Error explains in human words what failed and offers a way forward: retry, go back, contact support.
The gotcha most teams miss: 'no data yet' and 'no results for this filter' are different screens. The first wants a create button, the second wants a clear-filters button, and swapping them makes the product feel broken. Second gotcha: a loading state that flashes for 80ms is visual noise, so delay it a couple hundred milliseconds and hold it for a minimum once shown.
Ask AI for it
Implement all four states for this list view and show them in the same layout container so nothing jumps. Loading: skeleton rows matching the real row height and count, with a 200ms delay before showing and a 500ms minimum display once shown. Empty: a short headline, one sentence explaining why it is empty, and a primary action that creates the first item. Filtered-empty: a separate variant that names the active filters and offers a Clear filters button. Error: plain-language message, the error code in small text, and a Retry button that refetches. Keep copy under 20 words per state and use no illustrations bigger than 120px.