Cmpnts

Menu

Molecules

Empty State

The block shown where content would be when there is none, saying why and what to do next.


No saved plants

Save a plant from the catalogue to find it here later.

Code
HTML
<div class="empty-state">
  <div class="empty-state__visual">
    <span class="icon-box" aria-hidden="true">
      <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg>
    </span>
  </div>
  <div class="empty-state__content">
    <h2 class="empty-state__title subheading">No saved plants</h2>
    <p class="empty-state__description small-text">Save a plant from the catalogue to find it here later.</p>
  </div>
  <div class="empty-state__actions">
    <button type="button" class="button">Browse plants</button>
  </div>
</div>

Why it exists

A blank space leaves people guessing whether something broke, is still loading or really has nothing to show. An Empty State settles it: it says what is missing, why, and what to do next.

Most of its value is in the words, so the component stays out of their way. It lays out a visual, some text and actions, and each part styles itself. It has no padding of its own because it normally sits in something that does, such as a Card or a Table cell.

It isn’t a live region. One that arrives along with its content isn’t reliably announced, and if it were, the whole block would be read out when one short sentence would do. So the news goes in a status element that’s already on the page.

When to use

  • Where content would be and there is none: a search or filter miss, a first use, a cleared queue, a region that failed to load.
  • Not for a page-level error: that is a Banner with role="alert".
  • Not while content is still loading: a Skeleton holds its space.

Rules

  • A <div>, not a landmark. Use a <section> with a heading only when the Empty State is the whole content of a page or panel.
  • The heading level fits the page outline; the class sets the size. In a Table cell, the title can be a <p>.
  • When a search or filter empties a list, put the news in a role="status" element that is on the page from the start (“No plants match”, or the result count). The Empty State isn’t a live region: one added with its content isn’t reliably announced, and a whole block would be read out.
  • hidden works on it: show it with hidden = false, not an inline display.

Say What’s Empty and What to Do

No plants match “fern”

Check the spelling, or clear the filters to see all 40 plants.

Code
HTML
<div class="empty-state">
  <div class="empty-state__visual">
    <span class="icon-box" aria-hidden="true">
      <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Search"/></svg>
    </span>
  </div>
  <div class="empty-state__content">
    <h3 class="empty-state__title subheading">No plants match “fern”</h3>
    <p class="empty-state__description small-text">Check the spelling, or clear the filters to see all 40 plants.</p>
  </div>
  <div class="empty-state__actions">
    <button type="button" class="button">Clear filters</button>
  </div>
</div>
  • The title says what is empty: “No plants match “fern””, not “No results”.
  • The description says why, or what to do next.
  • At most one primary action. A first-use state shows the action that fills it.
  • An error that leaves a region empty can be a --danger Empty State with a “Try again” Button. A page-level error is a Banner with role="alert".

Say What Happened with Intent

All caught up

No plants need watering today.

Code
HTML
<div class="empty-state empty-state--success">
  <div class="empty-state__visual">
    <span class="icon-box" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg></span>
  </div>
  <div class="empty-state__content">
    <h3 class="empty-state__title subheading">All caught up</h3>
    <p class="empty-state__description small-text">No plants need watering today.</p>
  </div>
</div>

Intent tints the Icon Box and colours its icon (it sets --icon-box-intent). Colour never carries the meaning alone (WCAG 1.4.1): the icon and the title say what happened.

Placement

  • In a Card: inside .card__body. Use --compact in a small Card.
  • In a Table: one row, one cell with colspan spanning every column; keep the header row so the columns stay named.
  • In a narrow Sidebar: --compact and --start, or a .ui-compact region.
  • A slot or drop zone: --subtle.

No reminders

Add one to get a nudge before watering day.

No photos of this bed

Upload a photo to track how it grows.

No filters applied

Choose a filter to narrow the list.

Code
HTML
<!-- In a small card -->
<div class="card">
  <div class="card__body">
    <div class="empty-state empty-state--compact">
      <div class="empty-state__visual">
        <span class="icon-box" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Bell"/></svg></span>
      </div>
      <div class="empty-state__content">
        <h3 class="empty-state__title small-heading">No reminders</h3>
        <p class="empty-state__description small-text">Add one to get a nudge before watering day.</p>
      </div>
    </div>
  </div>
</div>

<!-- A slot or drop zone -->
<div class="empty-state empty-state--subtle">
  <div class="empty-state__visual">
    <span class="icon-box" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Upload"/></svg></span>
  </div>
  <div class="empty-state__content">
    <h3 class="empty-state__title subheading">No photos of this bed</h3>
    <p class="empty-state__description small-text">Upload a photo to track how it grows.</p>
  </div>
</div>

<!-- Aligned to the start, as in a narrow sidebar -->
<div class="empty-state empty-state--compact empty-state--start">
  <div class="empty-state__content">
    <h3 class="empty-state__title small-heading">No filters applied</h3>
    <p class="empty-state__description small-text">Choose a filter to narrow the list.</p>
  </div>
</div>

Do and Don’t

DoDon’t
Say what is empty: “No plants match “fern””.Write “No results”.
Say why, or what to do next.Leave people with a title and nothing to do.
Announce a search miss in a role="status" that is on the page from the start.Make the Empty State a live region.
Show at most one primary action.Offer several competing actions.
Show and hide it with hidden.Set an inline display.
Pair intent with an icon and a title that says what happened.Leave colour to carry the meaning.

In Storybook

See also

  • Card: A surface with named parts, such as a header, a body and a footer, for one thing a person can read, compare or act on.
  • Banner: One message with an intent, in one row, with an optional icon and actions.
  • Icon and Icon Box: A small glyph that helps people recognise something, on its own or in a frame.
  • Button: An action on the page, such as saving a Form, opening a Dialog or changing a setting.

Search the docs