Skip to main content

Design system components

EmptyState

Placeholder block for empty lists, zero search results, and first-run screens.

Status: stable. Group: display. Markdown version: /design-system/components/empty-state.md

When to use

EmptyState fills the space where content should be with an explanation and a way forward: a decorative icon, a real heading, up to two sentences of description, and an action slot for Buttons. Use sm inside panels and cards, md in content areas, lg on full pages. For failures use AlertBanner; EmptyState is for legitimate absence.

When not to use

  • Do not use EmptyState for errors or loading; AlertBanner owns failures and Skeleton owns loading.

Look-alikes

  • AlertBanner: Do not use EmptyState for errors or loading; AlertBanner owns failures and Skeleton owns loading.
  • Center: Use it for single focal content: Spinner, EmptyState, a logo lockup.
  • Skeleton: Do not use EmptyState for errors or loading; AlertBanner owns failures and Skeleton owns loading.

Props

EmptyState props
PropTypeDefaultDescriptionRequired
iconstringnonePhosphor icon name rendered decoratively above the title.No
titlestringnoneShort headline stating what is empty.Yes
descriptionstringnoneOne or two sentences explaining why, or what to do next.No
headingLevel"h2" | "h3" | "h4"h2Heading tag for the title. Defaults to h2; set it to fit the page outline.No
size"sm" | "md" | "lg"mdSize token. Defaults to md.No
childrenReact.ReactNodenoneAction slot; typically one primary Button, optionally a secondary.No

Variants

  • Available sizes: sm, md, lg (default md).
  • Allowed headingLevel values: h2, h3, h4 (default h2).

Invalid combinations

The contract records no invalid combinations.

Keyboard

EmptyState keyboard behaviour
KeyBehaviour
TabReaches actions in the slot.

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

EmptyState rules
LevelRuleHow it is checked
MUSTARIA: Title is a real heading; headingLevel must fit the page outline.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Icon is decorative (aria-hidden)Not yet verified: no evidence record. WCAG 4.1.2.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTEvery documented keyboard interaction works as specified.Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-11-04.
SHOULDName what is empty in the title ("No projects yet"), not a generic "Nothing here".Not stated in the contract.
SHOULDGive a way forward: an action button, or a description telling the user what will populate this space.Not stated in the contract.
SHOULDSet headingLevel so the title fits the page outline (h3 inside a card that sits under an h2).Not stated in the contract.
SHOULDKeep zero-search-results copy actionable: suggest clearing filters or broadening the term.Not stated in the contract.
SHOULD NOTDo not stack more than two actions; one primary path plus one escape hatch.Not stated in the contract.

Install and import

  • Install: npm install @digitaltableteur/react (version 0.9.1, restricted access on npm).
  • Import: import { EmptyState } from "@digitaltableteur/react";
  • Entry point: @digitaltableteur/react/feedback exports it too.
  • Styles: import @digitaltableteur/react/style.css once at the app boundary.
  • Also available as the custom element <dt-empty-state>; see the custom elements manifest.