Skip to main content

Empty State

An empty state fills a region that has no data yet: an empty list, zero search results, a first-run screen. It centres an optional icon in a muted disc, a title, a description and a row of actions, and scales all of them with one size.

import EmptyState from '@zuilib/components/empty-state'

Basic

The four parts are props. icon is decorative (aria-hidden); the title carries the meaning.

Loading example

Sizes

size scales the padding, the gap, the icon disc and the type together. An SVG without a size-* class is sized to fit the disc.

Loading example

Compound

The parts are also statics on EmptyState (and named exports). Use them for custom order or extra content; they inherit size from the root. titleAs / EmptyState.Title as render a heading tag when the empty state should appear in the document outline.

Loading example

Props

EmptyStateProps extends the <div> attributes of the root with:

PropTypeDefaultDescription
iconReactNodeDecorative glyph in a muted disc; aria-hidden
titleReactNode
titleAs'div' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6''div'Element the prop title renders as
descriptionReactNode
actionsReactNodeA centred, wrapping row of buttons / links
size'sm' | 'md' | 'lg''md'Scales padding, gap, icon disc and type; inherited by the parts
classNamestringMerged last, after the size classes
childrenReactNodeRendered after the prop-driven parts; the compound parts go here

Parts

PropTypeDefaultDescription
EmptyState.Iconspan propsThe muted disc; aria-hidden. SVGs without a size-* class are sized for the size
EmptyState.Titlediv props + as?: EmptyStateTitleTagas: 'div'Pass a heading tag to put it in the outline
EmptyState.Descriptiondiv propsMuted, max-w-prose; links inside are underlined foreground
EmptyState.Actionsdiv propsCentred flex-wrap row

Slots

SlotElementNotes
[data-slot="empty-state"]divRoot. data-size
[data-slot="empty-state-icon"]spanThe disc
[data-slot="empty-state-title"]div (or titleAs)
[data-slot="empty-state-description"]div
[data-slot="empty-state-actions"]div
/* Consumer CSS: square icon disc in brand colour */
[data-slot="empty-state-icon"] {
border-radius: var(--radius-md);
background-color: var(--primary);
color: var(--primary-foreground);
}

Tokens

TokenUsed for
--muted, --muted-foregroundIcon disc and description
--foregroundTitle and links in the description
--spacingPadding, gap and disc size are multiples of it
--text-xs/sm/base/lgType per size

Accessibility

  • Static content with no live role. When the empty state replaces results that just changed (a search coming back empty), pass role="status" so the change is announced.
  • The icon is aria-hidden; make sure the title states what is empty.
  • The title is a <div> by default because the component cannot know its outline level; use titleAs="h2" (or as on EmptyState.Title) when it should be a heading.
  • Put the primary action first in actions; the row is a normal tab sequence.
  • Skeleton: the placeholder while data is still loading.
  • Alert: a message with a status.
  • Button: the actions.