Skip to main content

The problem

A region with nothing in it is one of three genuinely different situations, and a reader cannot tell them apart unless the interface says which:
  1. Nothing here yet. The reader hasn’t created anything. The right next step is to create the first one.
  2. Nothing matched. Data exists; a filter, search, or query excluded all of it. The right next step is to widen or clear the narrowing.
  3. Something went wrong. A load or an action failed, and the region is empty because the attempt to fill it didn’t succeed. This is not this pattern’s job — see Error handling.
Conflating the first two is the most common failure: telling a brand-new account “no results” describes their account as a failed search, and telling a searching reader “get started” reads as a lost query, not a narrow one. Conflating either with the third is worse — a blank region with no explanation is indistinguishable from a bug, whichever of the three actually happened. This pattern is not the illustration. The pattern is knowing which of the three situations applies, and saying so in words, not only in a picture.

Deciding which case applies

Vocabulary

When this applies

  • A region that normally holds content currently has none, and the load that would have produced content completed successfully.
  • The reader benefits from knowing why the region is empty and, where one exists, what to do about it.
  • The region is large enough that a bare line of text would read as a rendering failure rather than a message — see EmptyState’s own guidance.

When it doesn’t

Structure

Behavior

Constraints

Content

Never fall back to the component’s default message (“No Records found!”) for either case — it names neither cause and satisfies none of the rules above. Always pass an explicit title.

Accessibility

  • The title is real text, not baked into the illustration — an illustration carrying the message is invisible to a screen reader. See EmptyState’s own accessibility section.
  • An empty state that appears in response to an action — clearing a filter, running a search — is announced. Nothing about the component announces itself; the region that swapped its content owns that announcement.
  • The illustration carries no information the text doesn’t already state; it is decorative.

Variations

Anti-patterns

The same message for a zero state and a no-results state. “No campaigns yet” shown to a reader who just typed a search that matched nothing tells them to go create something that already exists. An empty state shown during a load. The region says “nothing here,” then fills a moment later — the reader who read the first message already believes it and may navigate away before the real content arrives. A blank region with no explanation at all. Cheaper to ship than any of the three real cases, and indistinguishable from a bug no matter which of the three actually happened. Using an empty state to quietly absorb a failure. Showing “nothing here yet” when the actual cause is a failed request hides that something needs fixing, and sends the reader down the wrong path — creating a record that already exists, or waiting for data that will never arrive because the load never ran.

Known issues

Gaps in the current rules

  • Whether a zero state’s resolving action should differ when the reader lacks permission to create the first record, beyond simply omitting the button — Variations names the omission but not what replaces it.
  • What a no-results state should say when the search or filter is itself malformed (an invalid date range, a query with no valid tokens), as opposed to well-formed but unmatched.
  • Whether a table’s sortable, filterable controls should stay interactive during a zero state, or disable until content exists.

Why it works this way

Naming which of the three cases applies is the whole job, because the cost of getting it wrong is asymmetric and silent. A reader told “no results” when they’ve created nothing yet, or told “get started” when their search just missed, doesn’t see an error — they see an interface that’s confidently wrong, and correcting that requires them to already suspect it, which most readers won’t. The failed-load case is routed elsewhere rather than folded in as a fourth option, because “empty” and “broken” are not degrees of the same thing. This pattern never has to guess whether an empty region is empty on purpose — that distinction belongs to Error handling, which knows whether the load actually succeeded. EmptyState, the component this pattern composes for both cases. Empty state copy, the copy rules Content follows rather than restates. Error handling, for the failed-load case this pattern explicitly excludes. Welcome / empty state, the AI-driven counterpart for an agentic panel’s first run or empty result.

Status

Exemplar page — first pass. This is a proposal for review, not established policy. No Titan design-library review or shipped Invoca screen backs this page — it composes the real EmptyState component and the real Empty state copy content rules, and cites their constraints rather than restating them. Where this pattern’s guidance is new, it is a proposal to check against a real screen, not a decision already confirmed.
Last modified on September 17, 2026