Empty States

Empty states communicate when there’s no content to display. A good empty state guides users toward their next action instead of leaving them confused.


Basic Empty State

A centered message with optional icon and action.

No items yet

Get started by creating your first item.

<div class="EmptyState">
    <div class="EmptyState-icon">
        <i class="ph ph-package"></i>
    </div>
    <h3 class="EmptyState-title">No items yet</h3>
    <p class="EmptyState-description">Get started by creating your first item.</p>
    <button class="Button Button--primary">Create Item</button>
</div>

With Illustration

Replace the icon with a custom illustration for more personality.

Your inbox is empty

When you receive messages, they'll appear here.

<div class="EmptyState">
    <div class="EmptyState-illustration">
        <img src="empty-inbox.svg" alt="">
    </div>
    <h3 class="EmptyState-title">Your inbox is empty</h3>
    <p class="EmptyState-description">When you receive messages, they'll appear here.</p>
</div>

Compact Variant

For smaller containers like sidebars or cards.

No documents

<div class="EmptyState EmptyState--compact">
    <div class="EmptyState-icon">
        <i class="ph ph-file-text"></i>
    </div>
    <p class="EmptyState-description">No documents</p>
    <button class="Button Button--primary">Upload</button>
</div>

Search Results

When a search or filter returns no matches.

No results found

We couldn't find anything matching "quantum flux capacitor". Try different keywords or check for typos.

<div class="EmptyState">
    <div class="EmptyState-icon">
        <i class="ph ph-magnifying-glass"></i>
    </div>
    <h3 class="EmptyState-title">No results found</h3>
    <p class="EmptyState-description">Try different keywords or check for typos.</p>
    <div class="Layout-cluster">
        <button class="Button">Clear Search</button>
        <button class="Button Button--primary">Browse All</button>
    </div>
</div>

Error State

When something goes wrong loading content.

Unable to load data

Something went wrong on our end. Please try again or contact support if the problem persists.

<div class="EmptyState EmptyState--error">
    <div class="EmptyState-icon">
        <i class="ph ph-warning-circle"></i>
    </div>
    <h3 class="EmptyState-title">Unable to load data</h3>
    <p class="EmptyState-description">Something went wrong...</p>
    <button class="Button Button--primary">Retry</button>
</div>

First-Time User

Onboarding empty states that guide new users.

Welcome to your dashboard!

You're all set up. Here's how to get started:

1 Create your first project
2 Invite team members
3 Start collaborating

In Cards

Empty states within card components.

No data to display

No team members

Invite people

In Tables

Empty state for table components.

Name Status Date Actions

No records found

Create a new record to get started.


Best Practices

Content Guidelines

Element Guideline
Title Clear, concise — what’s missing
Description Why it’s empty + what to do next
Action Primary CTA to resolve the state
Tone Helpful, not apologetic

Do

  • Explain the situation — Tell users why there’s no content
  • Provide a clear action — Give them something to do
  • Use appropriate visuals — Icons or illustrations that match context
  • Keep it simple — One primary action, maybe a secondary
  • Match the context — Use compact variant in small containers like cards or sidebars
  • Differentiate error from empty — Use the error variant when content failed to load vs. simply not existing yet

Don’t

  • Leave it blank — An empty container is confusing
  • Be overly verbose — Keep copy short and scannable
  • Use generic messages — “No data” doesn’t help anyone
  • Hide the state — Make it visible so users understand
  • Stack multiple empty states — If a page has several empty sections, consolidate into one page-level message
  • Blame the user — Say “No results found” not “You didn’t search correctly”

CSS Reference

/* Base */
.EmptyState {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-8);
  min-height: 200px;
}

.EmptyState-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background-color: var(--bg-s);
  color: var(--fg-3);
  font-size: 2rem;
  margin-bottom: var(--space-4);
}

.EmptyState-illustration {
  margin-bottom: var(--space-4);
}

.EmptyState-illustration img,
.EmptyState-illustration svg {
  max-width: 160px;
  height: auto;
}

.EmptyState-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--fg);
  margin: 0 0 var(--space-2);
}

.EmptyState-description {
  font-size: 0.9rem;
  color: var(--fg-3);
  max-width: 320px;
  margin: 0 0 var(--space-4);
}

/* Compact variant */
.EmptyState--compact {
  padding: var(--space-4);
  min-height: auto;
}

.EmptyState--compact .EmptyState-icon {
  width: 48px;
  height: 48px;
  font-size: 1.5rem;
  margin-bottom: var(--space-3);
}

.EmptyState--compact .EmptyState-title {
  font-size: 1rem;
}

.EmptyState--compact .EmptyState-description {
  font-size: 0.85rem;
  margin-bottom: var(--space-3);
}

/* Error variant */
.EmptyState--error .EmptyState-icon {
  background-color: oklch(55% 0.2 25 / 0.1);
  color: oklch(55% 0.2 25);
}