Mobile components

Empty states

An empty state is what a screen shows before it has any content. It explains why the screen is blank and offers the one action that changes that.

When to use it

Use an empty state anywhere a list, a search, or a whole screen can legitimately have nothing in it: an inbox before the first message, a folder before the first file, a search with no matches.

An empty screen with nothing on it reads as a loading failure. An empty state turns the same screen into an explanation.

Distinguish the three cases, because they need different words:

CaseMessageAction
Nothing yetExplain what will appear hereThe thing that creates the first one
Nothing foundSay what was searched forClear the search or widen it
Nothing to doSay the work is doneOften none

Anatomy

No Messages

Messages you receive will appear here.

Start a Conversation
<div class="p-empty-state">
<i class="p-empty-state__glyph ph-bold ph-tray"></i>
<h2 class="p-empty-state__title">No Messages</h2>
<p class="p-empty-state__message">Messages you receive will appear here.</p>
<a class="p-button p-button-touch-large p-button-glass-prominent p-empty-state__action" href="/new/">
  Start a Conversation
</a>
</div>
PartValue
Glyph41px, in the accent
Title22px, weight 590, line height 28px
Message22px, weight 510, rgba(60,60,67,0.60)
Message width30ch, so a centered sentence stays readable
Badge50px circle, the glyph’s tint at 15%, holding a 22px glyph
ActionFull width to 330px, 52px tall, full capsule, no drop shadow, a glow rising into the bottom edge
Padding32px vertical, 34px horizontal

The message is the same size as the title and one weight lighter, which is unusual. Most interfaces drop the supporting text a size or two. iOS keeps both at 22px and separates them with weight and color instead.

The action is an ordinary touch button with .p-empty-state__action widening it and setting the 52px height. Compose it with any button style. The prominent glass button, .p-button-glass-prominent, is the usual choice, since an empty state has exactly one thing worth doing. A plain filled button works too, and gets the same glass lines along its edges.

Variants

No Results

No files match “budget”.

All Caught Up

You have read everything in this folder.

The glyph and the action are both optional. A “nothing found” state often has no action worth offering, and a “nothing to do” state often needs no glyph.

.p-empty-state-compact drops the glyph to 22px and sets it in a 50px circle washed with its own tint at 15%, for an empty state inside a panel or a popover rather than filling a screen. The same badge is available on its own as .p-empty-state__badge:

<span class="p-empty-state__badge" aria-hidden="true"><i class="ph-bold ph-heart"></i></span>

The glyph does not have to be blue. Set --p-empty-glyph on the empty state to any system color and the glyph and its badge follow: style="--p-empty-glyph: var(--p-sys-pink)".

.p-empty-state-fill gives the block flex: 1 and a 240px minimum, so an empty state inside a list or a sheet centers in that region instead of sitting at the top of it.

.p-empty-state-anchored pushes the action to the bottom of the available space, which is where iOS puts it on a full screen.

Writing the content

Title in title case, a few words, naming what is missing. “No Messages”, not “Nothing here”.

Message as one complete sentence explaining what will appear or why nothing did. Say what was searched for when the state is a search result; “No files match “budget"" is useful in a way that “No results” is not.

Avoid apologising, and avoid exclamation marks. The screen is empty because of where the person is, not because something went wrong.

Dark mode

The title moves to rgba(255,255,255,0.92), the message to rgba(235,235,245,0.60), and the glyph from #0088FF to #0091FF.

Accessibility

Use a real heading for the title so the empty state appears in the page outline, and keep the level consistent with the screen it replaces.

The glyph is decoration next to a title that already says what is missing, so mark it aria-hidden="true".

When an empty state replaces a list that was previously populated, put it in a container with aria-live="polite" so a screen reader announces the change rather than leaving the person in a silent empty region.

Copied