Empty State

Free

Full-page or inline empty states with icons, titles and action buttons.

</>sv-empty-state emptyplaceholderfeedback
import { SvEmptyStateComponent } from '@styloviz/empty-state';

Demo & usage

Basic usage

Usage example — open the gallery for the full interactive demo.

An interactive demo for this component lives in the gallery.

Open live demo

More examples

With actions

example.htmlAngular
<!-- The FIRST action is primary and the rest are secondary unless they
     say otherwise. Three primary buttons side by side is no hierarchy:
     the user reads all three to find the one the page expects. -->
<sv-empty-state
  icon="folder"
  title="No projects yet"
  message="Create your first project to get started."
  [actions]="emptyActions"
  (actionClick)="create()" />

A filtered zero, which is a different fact

example.htmlAngular
<!-- "Nothing here yet" when the user has filtered is a lie that reads
     as a bug: it tells a customer with 4,000 orders they have none
     because they mistyped a search term - and the cheerful inbox glyph
     agrees with it.

     Pass the filters and the copy becomes "No matching results", the
     glyph becomes a search, and the filters themselves are echoed with
     one button to drop them. The reason is inferred from them, so the
     mistake of echoing filters under "Nothing here yet" is impossible. -->
<sv-empty-state
  [activeFilters]="activeFilterLabels()"
  (clearFilters)="resetFilters()"
  [actions]="emptyActions"
  (actionClick)="create()" />

The other two reasons

example.htmlAngular
<!-- An error and a permission wall are not empty containers either;
     each gets its own copy and glyph. -->
<sv-empty-state reason="error" />
<sv-empty-state reason="no-access" />

When to use

  • Communicating that a list, search or section has no content — and what to do next.
  • First-run states, empty searches, cleared inboxes.
  • For load failures specifically, use the Result component (error status).

Async states

  • retry
  • offline

Inputs

NameTypeDefaultDescription
titlestring''Main heading text. Falls back to copy chosen from `reason`. The default is now empty rather than `'Nothing here yet'`: that string was the DEFAULT for a filtered list too, which is the whole of `resolvedTitle()` picks the sentence that is true.
messagestring''Supporting message under the title. Falls back to copy from `reason`.
reasonEmptyStateReason'no-data'Why this container has nothing in it. Drive it from whether a filter or search is active — not from the row count.
activeFiltersreadonly string[][]The filters currently narrowing the list, in the user's words — `['Status: Overdue', 'Owner: Dana']`. ECHOING THEM TURNS A DEAD END INTO ONE CLICK. "No matching results" is unanswerable on its own: the user cannot see WHY, and the filter that is hiding everything is usually one they set three screens ago and have forgotten. Naming them, with a way to drop them, is the whole fix. Strings, not a filter model. Only the host can render a date range or a facet id as words a person recognises, and a kit that tried would print `status_id: 4`.
clearFiltersLabelstring | null'Clear filters'Label for the built-in clear-filters button. `null` renders none.
offlinebooleanfalseThe device is offline. Takes precedence over `reason`.
retryLabelstring | nullnullLabel for the preset's retry button, offered for `reason="error"` and for `offline` — the two causes a second attempt can fix. `null` renders none.
iconEmptyStateIcon'inbox'Built-in icon preset. Set to `'custom'` and provide `customIcon` to use your own SVG.
customIconstring''Icon-library NAME — required when `icon === 'custom'`, ignored otherwise. BREAKING (icon sweep): was `iconPath`, a raw `<path d="…">`, alongside an `iconViewBox` that is now deleted. An unresolved name draws no `<svg>` at all, so the decorative ring keeps its shape.
showRingsbooleantrueShow the decorative concentric-ring background behind the icon.
sizeEmptyStateSize'md'Overall size.
layoutEmptyStateLayout'vertical'Content stacking axis.
borderedbooleantrueWhether to render a card surface (border + background + rounded corners) or let the component blend into its parent.
customClassstring''Additional CSS classes on the root element.
actionsEmptyStateAction[][]CTA buttons rendered below the message. Maximum 3 — first one is typically primary, rest secondary/ghost.

Outputs

EventPayload typeDescription
actionClickstringEmitted when any action button is clicked, carrying the action's `id`.
clearFiltersvoidThe built-in clear-filters button was pressed.
retryvoidThe preset retry button was pressed (`retryLabel`).

Customization & theming

  • Inline or full-page layout.
  • Icon, title, description and actions.
  • `reason` (`no-data` · `no-results` · `error` · `no-access`) picks the copy AND the glyph when you do not state them — a cheerful inbox over "no matching results" says "you have nothing" when the truth is "your filters match nothing". Passing `[activeFilters]` infers `no-results` by itself.
  • `[activeFilters]` echoes the filters narrowing the list, as chips, with a `(clearFilters)` button beside them: "No matching results" is unanswerable on its own, and the filter hiding everything is usually one the user set three screens ago. Strings rather than a filter model, because only the host can render a date range as words a person recognises.
  • Action hierarchy by position: the first action is primary, the rest secondary, unless an action states its own `style`.
  • 12 built-in icon presets, or `icon="custom"` with `customIcon` naming any icon-library glyph.
  • Custom illustration slot.

Best practices

  • Do: Name the cause in the copy, because the component cannot: first-use, no-results-for-this-filter, no-permission and error look identical today (one neutral palette, one decorative icon, `role="region"`). "Nothing here yet" is right for exactly one of those four and actively misleading for the other three.
  • Do: For a filtered zero, echo the active filters and offer to clear them. It is the difference between a dead end and one click.
  • Do: Pair the empty message with a clear primary action to move forward.
  • Do: Distinguish "no data yet" from "no results for this filter".
  • Don't: Don't leave a blank area — an empty state reassures users nothing is broken.

Accessibility

  • Clear heading hierarchy.
  • Decorative icon hidden from assistive tech.
  • Actions are labelled buttons/links.

Feedback on Empty State

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.