Skip to content

HyEmptyState ​

Usage examples on this page are written for Lit / plain HTML (<hy-empty-state>). The same component ships as HyEmptyState in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

A placeholder for "no data / no results / error / loading" regions.

Collapses the hand-rolled empty + load-state markup duplicated across an app (icon/illustration + heading + body + actions) into one element. A state axis (empty | loading | error) absorbs the {loading}…{error}…{empty} triplet with a built-in spinner and retry button; a variant axis presets the icon + copy per scenario.

Key Features:

  • Scenario presets (no-data, no-results, error, not-found, success, offline)
  • Async-state mode (loading → built-in spinner; error → retry button firing retry)
  • Search-aware no-results via the query prop
  • Compact (inline) vs medium (full-region) sizes
  • A design system can upload a brand image per variant, drawn in place of the icon on a medium empty state while the media slot is empty
  • An illustration of the app's own in the media slot (an <img>, the file for the surface's color mode chosen by the app)
  • Slots for media / actions / footer, and the default slot for a richer description (the heading is the heading property)

Accessibility: built in ​

  • role="status" (implicit aria-live="polite") so a list becoming empty after filtering is announced to screen readers
  • High contrast + forced-colors support

Accessibility: your part ​

  • Mark an hy-icon in the media slot decorative. The heading already says what it means.
  • Do not move focus into the empty state unless the person's own action produced it.

When to use

  • A region with nothing in it yet, with the action that fills it: no projects, no messages.
  • A search or a filter that matches nothing, with variant="no-results".
  • A region whose content failed to load, with state="error" and a retry.

Do

  • Say what people can do next in the description.
  • Use size="compact" in a panel, a row or a small region.

When not to use

  • A save, rename, add or delete that failed while the content is still there: hy-toast or an inline hy-alert.
  • Loading a region whose layout is known: hy-skeleton in the shape of the content. Keep state="loading" for a small region or an unknown shape.
  • A condition about content that is still shown: hy-alert.
  • A failed load with no function to re-run: variant="error" alone, which shows no retry button. Use state="error" only when retry reloads the region.

Examples ​

No-data with an action ​

html
<hy-empty-state variant="no-data" heading="No design systems yet">
  Create your first design system to get started.
  <hy-button slot="actions" variant="brand">New design system</hy-button>
</hy-empty-state>

Search-aware no-results ​

html
<hy-empty-state variant="no-results" query="brutalist"></hy-empty-state>

The async triplet, one element ​

html
<hy-empty-state state="loading"></hy-empty-state>
<hy-empty-state state="error"></hy-empty-state>
<hy-empty-state state="empty" variant="no-data"></hy-empty-state>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
variantvariant'no-data' | 'no-results' | 'error' | 'not-found' | 'success' | 'offline' | 'coming-soon''no-data'Scenario preset determining the default icon and copy.
statestate'empty' | 'loading' | 'error''empty'Async-state mode. loading shows a spinner; error shows the error layout with a retry button.
sizesize'compact' | 'medium''medium'Size / density. compact for inline placements (empty rows, side panels); medium for centered full-region placements.
headingheadingstring | undefined—Heading text. An empty string counts as not set: the variant's default heading shows (and, while loading, the default Loading… region label).
descriptiondescriptionstring | undefined—Description text. The default slot wins if both are provided. An empty string counts as not set: the variant's default description shows.
queryquerystring | undefined—Search query. For variant="no-results", drives the default No results for "…" heading.
labellabelstring | undefined—Accessible label for the region (applied as aria-label).
queryHeadingTextquery-heading-textstring'No results for "{query}"'The default variant="no-results" heading when query is set, a template: {query} is replaced by the query. Use for internationalization.
loadingLabelloading-labelstring'Loading…'The region's accessible name in state="loading" when no heading is set. Use for internationalization.
retryLabelretry-labelstring'Retry'Label of the built-in retry button (state="error"). Use for internationalization.
strings—Partial<EmptyStateStrings>{}The built-in copy — each variant's default heading and description — merged over DEFAULT_EMPTY_STATE_STRINGS: set only the keys you translate. An explicit heading / description still wins. The query heading (query-heading-text), the loading name (loading-label) and the retry button (retry-label) stay separate properties. Property only (no attribute). Use for internationalization.

Events ​

EventDetailDescription
retry—Fired when the built-in retry button (shown in state="error") is clicked. Detail: {}

Slots ​

SlotDescription
mediaThe visual — icon, illustration, or animation. Defaults to the variant's icon, or the design system's image for it. Leave it empty unless its content means something of its own (a 404's number): anything here hides that image.
defaultThe description body (richer than the description prop).
actionsPrimary + secondary action buttons.
footerHelp link / "learn more".

CSS Parts ​

PartDescription
baseThe empty-state region wrapper.
mediaThe media (icon/illustration) container.
titleThe heading element.
descriptionThe description element.
actionsThe actions slot container.
footerThe footer slot container.

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-empty-state-padding-container-lgvar(--hy-padding-container-lg)Padding around the region.
--hy-empty-state-padding-container-smvar(--hy-padding-container-sm)Padding around the region.
--hy-empty-state-gap-container-mdvar(--hy-gap-container-md)Gap between media / title / description / actions.
--hy-empty-state-gap-container-smvar(--hy-gap-container-sm)Gap between media / title / description / actions.
--hy-empty-state-foreground-default-restvar(--hy-foreground-default-rest)Heading color.
--hy-empty-state-description-foreground-subtle-restvar(--hy-foreground-subtle-rest)Description / footer color.
--hy-empty-state-media-foreground-subtle-restvar(--hy-foreground-subtle-rest)Default media icon color.

Built with Lit. Documented with VitePress.