Empty states that don't look broken
Agents design for full data. Your users open the app and see zero data. The empty state is the first screen every real user meets, and your agent has never met a real user.
Populated
Recurring revenue, the chart, the customer table. The state your agent was designing for the whole time.
What agents ship
A gray $0, axes with nothing on them, a table header with no rows. Every element is technically present, and the screen reads as broken.
Designed
No zero, no dead axes. The card title and date range stay, so the screen reads as finished. One crafted object, one sentence naming the condition that fills it, one action.
Add to CLAUDE.md
The standing rule. Paste it into CLAUDE.md, AGENTS.md, or .cursorrules.
## Empty states Every screen that renders data ships with a designed empty state, built in the same pass as the populated state. Never as a follow-up. 1. Never render a zero as the headline. "$0" above a flat chart reads as failure, not as a new account. In the empty state, the metric is replaced, not zeroed. 2. Delete dead scaffolding. Empty chart axes, table headers with no rows, and skeleton chrome read as broken UI. Remove them from the empty state entirely. 3. Keep the outer frame. The card title, the date range control, and the surrounding navigation stay, so the user still knows where they are and that the screen finished loading. 4. One sentence, written as a fact about the future. Say what will appear here and name the exact condition that fills it. Good: "Revenue will appear here once your first customer is charged." Bad: "No data yet." / "Nothing here!" / "Get started with revenue tracking." 5. Exactly one action, and it must be the action that fills this panel. Not "Learn more." Not a primary and a secondary button. One. 6. No emoji. No stock illustration. No dashed-border upload box. If the state needs an object, use one brand-owned render at low contrast, under a quarter of the panel height. 7. Same padding, type scale, and border radius as the populated state. An empty state is not a special layout. 8. Distinguish empty from filtered from failed. "No customers yet" (empty), "No customers match these filters" plus a clear-filters action (filtered), and "Couldn't load customers" plus retry (error) are three different screens. 9. When you touch any existing screen that renders data, check its empty state before you finish. If it renders a zero, dead axes, a header-only table, a bare "No data", or nothing at all, fix it in the same change. Do not leave a screen you edited in a state these rules would reject. Before finishing any data screen, render it with an empty dataset. If it looks broken, unfinished, or like an error, it is not done.Download the raw .md
Run the audit
A one-off sweep of the app you already shipped. Paste this into your agent as a message, not into CLAUDE.md.
Audit every screen in this codebase for empty states.
1. Find every view that renders a collection, metric, chart, table, list, feed,
search result, or detail panel populated from a data source.
2. For each one, work out what actually renders when that source returns
nothing: an empty array, null, a zeroed metric, or no response at all. Read
the component, do not guess from the file name.
3. Classify each screen:
- designed: passes the empty-state rules
- undesigned: renders a zero, dead axes, a header-only table, a bare
"No data", or an unstyled string
- missing: renders nothing, a blank region, or crashes
4. Check the filtered-empty path and the error path separately. A screen can
have a designed empty state and still fall over when a filter matches
nothing or the request fails.
5. Report one table, sorted with the most-visited screens first:
file path | screen | what renders when empty | classification | the one
sentence and one action you would use instead
Do not change any code in this pass. Report the table, then stop and wait.Why this one rule changes the whole app
Every dashboard, table, list, inbox, and chart in your product has an empty state. An agent generates all of them from the same default, so one instruction propagates across every screen at once. It is the highest leverage line you can add to an agent instruction file.
When the table comes back from the audit, fix them highest-traffic first, one commit per screen, so each is reviewable on its own. Most teams find between eight and twenty screens in the undesigned or missing columns on the first run. That is not a failure of your agent. Nobody prompted for the zero-data case, so nobody got it.
Checklist
- No zeroed metric standing in for the empty state
- No empty axes, no header-only tables, no ghost rows
- Card title and controls still present
- One sentence naming the condition that fills the panel
- Exactly one action, and it fills this panel
- No emoji, no stock illustration
- Padding and type scale match the populated state
- Empty, filtered, and error states are distinct
- Existing screens audited, not just the one you are building
When a rule isn't enough
The screens a rule can't fix, I redesign myself.
Two weeks, $3,000. Your real screens, redesigned on the Krit canvas and shipped as a pull request into your repo. You keep the tool.
Book a free product audit