Basics

What is an empty state — and why it's the first screen every user sees

Illustration: the empty screen as the first conversation with a user

You built an app. Opened it, added a couple of tasks, looks great. You show a friend — and their screen is blank. No tasks at all, because they signed up thirty seconds ago.

Here's the unexpected part: the first screen every new user sees is empty. Always. It is literally the most visited screen in your app, and usually the only one nobody designed.

That blank screen is called an empty state, and it isn't "no data". It's a conversation.

Three different kinds of emptiness, all treated the same

One word, three very different situations — and the text has to differ.

First run. There's no data because the person just arrived. They don't know what to do and are waiting for a hint. This needs one line about what will live here, plus a button that creates it.

Nothing found. Data exists, but a search or filter returned nothing. This person isn't a beginner — they're looking for something. They need to know what narrowed the results and how to widen them.

All done. The list is empty because the tasks are finished. That's not a problem, that's a reward — and the copy should sound like one.

Write "No data" in all three and two of those screens work against you. The first-run person concludes the app is broken; the filtering person concludes the database is empty.

The big mistake: emptiness instead of loading

The most common and most damaging variant is showing "Nothing found" while the data is still in flight.

It looks like this: the screen mounts, the component renders with an empty array, prints "No records", and half a second later the data arrives and replaces the message with a list.

In that half second the person read that there are no records. They either left, or decided the app lies to them. Nielsen Norman Group research describes exactly this scenario: the interface reports a false system status and then quietly swaps it — trust drops harder than it would from honest waiting.

One check fixes it. A list doesn't have two states, it has at least three:

  • loading — the request is running, show a skeleton or a spinner;
  • empty — the request finished and there genuinely is nothing;
  • error — the request failed, which isn't emptiness at all.

The beginner's mistake is collapsing loading and empty into a single items.length === 0. Split them with an explicit flag and half the problem disappears.

What to write on an empty screen

A working structure — three elements, nothing extra:

  1. What this place is. One line: "Your saved articles will live here."
  2. Why it's empty right now. "You haven't saved anything yet" is not the same message as "Nothing matches the 'this week' filter."
  3. One action. A button that creates the first item. Exactly one: two equal offers on an empty screen is a choice nobody is ready to make.

What not to do: a full-screen onboarding tour, three links reading "Docs / Video / Community", and a big sad illustration with no text. A picture answers none of the questions and takes all the space.

There's a useful side effect: the empty screen is almost the only place where showing off unused features is welcome. The person isn't busy with a task — they're looking around. That's exactly why mature products offer templates and demo data there.

Demo data: help or harm

The tempting move is to fill the empty list with examples so people can see "how it'll look". Sometimes brilliant, sometimes a bug factory.

It works when: examples are clearly marked as examples, can be removed in one action, and never leak into statistics.

It breaks when: demo tasks are indistinguishable from real ones. People start editing them, then wonder why the counter says seven tasks instead of three — and you spend half a day tracing rows in the database that nobody created.

For a first project — at MVP scale — text and a button are enough. Add demo data once you know what people actually find confusing.

How to check your empty states in five minutes

Open the app in a private window and walk the path of a brand-new person, with zero records. Then search for a word that definitely doesn't exist. Then turn off the network and reload.

Three screens, three different messages. If two of them look the same, you've found work to do. This is also the cheapest way to check the idea before building further: if a newcomer has nothing to do on the first screen, the problem isn't the design.

Do I need an illustration on an empty screen?

Not necessarily. Text and a button always work; a picture is an accent. If the drawing pushes the explanation below the fold, drop it.

What if the request fails?

Then it isn't an empty state. An error is a separate screen: what happened, plus a Retry button. Show "Nothing found" instead of "Couldn't load" and the person will go hunting through their filters while the problem is the network.

What if data arrives in chunks?

Then don't show the empty state until loading is done — otherwise it flashes and vanishes. Same principle as optimistic UI: only show confidently what you're actually confident about.

Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app
KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →