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.
| Prop | Type | Default | What it does |
|---|---|---|---|
icon | ComponentType | An icon component, drawn at the thin weight in a round well. | |
illustration | ReactNode | A node rendered above the text instead of the icon. Wins over icon. | |
title | string | The 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. |
description | string | A line of text-fg-muted under the title. | |
action | ReactNode | A 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. Setasto 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