Gesso
Feedback

Empty state

A centered placeholder for a region with nothing to show, with an icon or illustration, a title, a description, and an action.

Empty state fills a table, a list, or a widget that has no rows yet, or none that match, and tells the reader what the space is for and what to do next. It stacks an icon in a round well, a title, a description, and an action, all centered. Prefer the icon inside widgets and tables, and pass your own illustration for a page-level drawing.

No files yet

Drop a file here or create one to get started.

Usage

import { FolderOpen } from '@phosphor-icons/react';
import { EmptyState } from '@/components/ui/empty-state';

<EmptyState
  icon={FolderOpen}
  title="No files yet"
  description="Drop a file here or create one to get started."
/>

Icon or illustration

icon takes an icon component, not an element, so the well can size it, and draws it in text-fg-muted inside a round bg-surface-sunken well: 40px at sm, 56px at md, and 80px at lg. The icon is at the thin weight in the larger wells and regular at sm, where a thin stroke would fade. Because the prop is a component, set it from a client component, as with Button's icons.

illustration takes any node, such as an SVG, and renders it above the text in place of the icon and its well. When both are set the illustration wins. The kit ships no illustrations, so bring your own.

children render between the text and the action, for something the props do not cover, like a list of suggestions.

Subtle or bordered, small to large

variant="subtle", the default, is unframed and sits directly on its surroundings. variant="bordered" adds a dashed border-border-strong and a bg-surface-raised wash at 64%, for a drop zone or a list placeholder that needs an edge. Both are rounded-lg.

size sets the scale. md is the default, with 48px of vertical padding, a 280px text column, a text-heading-5 title, and a text-body-sm description. lg has 80px of vertical padding, a 360px column, a text-heading-3 title, and a text-body-md description, and fits a whole page or a drop zone. At both, the title is in font-display and the description in font-body.

No results

Try a different query or clear the filters.

sm is for a small space inside something else, like a card's image slot, a side panel, or a popover. It has 24px of vertical padding, a 240px column, a text-body-sm title in medium weight, and a text-caption description, all in font-body, so it reads as part of the panel and not as a heading over it. The email blocks' picture placeholder uses these same sizes in the letter's own colors.

No image

Upload one or paste a link.

Nothing selected

Pick a row to see its details.

Props

Empty state takes every <div> attribute, plus these.

PropTypeDefaultWhat it does
iconComponentTypeAn icon component, drawn at the thin weight in a round well.
illustrationReactNodeA node rendered above the text instead of the icon. Wins over icon.
titlestringThe heading, an <h3> unless as says otherwise.
as"h2" | "h3" | "h4" | "h5" | "h6" | "p""h3"The title's element, so it fits the page's outline.
descriptionstringA line of text-fg-muted under the title.
actionReactNodeA control under the text, usually a Button.
variant"subtle" | "bordered""subtle"Unframed, or a dashed border on a raised wash.
size"sm" | "md" | "lg""md"The spacing, well, and type scale.

Accessibility

  • The root is a plain <div> with no role, so nothing is announced when it appears, and a region that empties after a search or filter is silent. If a person just ran that search, tell them in a live region of your own.
  • The title is an <h3> by default. Set as to the level that fits the outline, or "p" when it should not be a heading.
  • The icon's well is aria-hidden, since the icon is decorative and the text carries the meaning.
  • The action is whatever you pass, so give it a name that says what it does, like "New file". Empty state adds no focus or target size of its own.
  • Nothing animates.
  • The dashed border of the bordered variant is a border color, which forced colors repaints as ordinary text, so it still draws.

When to use something else

  • Alert for a message about content that is present, like a warning above a table, rather than a table with no rows.
  • Skeleton while the content is still loading. Show an empty state only after the load finishes with nothing, so it is not seen for a moment first.
  • Toaster for the result of an action, like "File deleted". A toast goes away, and an empty state stays as long as the region is empty.
  • A Dialog is for a decision, and an empty state is never a blocking message.

Install

shadcn add @gesso/empty-state

On this page