Empty State
FreeFull-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 demoMore examples
With actions
example.htmlAngular
9 lines
<!-- 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
14 lines
<!-- "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
4 lines
<!-- 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
| Name | Type | Default | Description |
|---|---|---|---|
| title | string | '' | 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. |
| message | string | '' | Supporting message under the title. Falls back to copy from `reason`. |
| reason | EmptyStateReason | 'no-data' | Why this container has nothing in it. Drive it from whether a filter or search is active — not from the row count. |
| activeFilters | readonly 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`. |
| clearFiltersLabel | string | null | 'Clear filters' | Label for the built-in clear-filters button. `null` renders none. |
| offline | boolean | false | The device is offline. Takes precedence over `reason`. |
| retryLabel | string | null | null | Label for the preset's retry button, offered for `reason="error"` and for `offline` — the two causes a second attempt can fix. `null` renders none. |
| icon | EmptyStateIcon | 'inbox' | Built-in icon preset. Set to `'custom'` and provide `customIcon` to use your own SVG. |
| customIcon | string | '' | 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. |
| showRings | boolean | true | Show the decorative concentric-ring background behind the icon. |
| size | EmptyStateSize | 'md' | Overall size. |
| layout | EmptyStateLayout | 'vertical' | Content stacking axis. |
| bordered | boolean | true | Whether to render a card surface (border + background + rounded corners) or let the component blend into its parent. |
| customClass | string | '' | Additional CSS classes on the root element. |
| actions | EmptyStateAction[] | [] | CTA buttons rendered below the message. Maximum 3 — first one is typically primary, rest secondary/ghost. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| actionClick | string | Emitted when any action button is clicked, carrying the action's `id`. |
| clearFilters | void | The built-in clear-filters button was pressed. |
| retry | void | The 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.