EmptyState
Centered placeholder block for 'no data yet' and 'no results' states, built from an optional icon, a heading, supporting text, and an optional call-to-action.
Playground
No items yet
Get started by adding the first item.
<EmptyState
description="Get started by adding the first item."
title="No items yet"
>
{#snippet cta()}
<Button intent="primary">
<PlusIcon />
Add item
</Button>
{/snippet}
</EmptyState>01 Examples
With icon and CTA
No apartments yet
Get started by adding the first apartment.
<EmptyState
icon={BuildingIcon}
title="No apartments yet"
description="Get started by adding the first apartment."
>
{#snippet cta()}
<Button intent="primary"><PlusIcon />Add apartment</Button>
{/snippet}
</EmptyState>Compact — for inline empty rows
No matches
Try adjusting your filter.
<EmptyState
density="compact"
icon={FunnelIcon}
title="No matches"
description="Try adjusting your filter."
/>Embedded inside a Card
Recent activity
Nothing here yet
New events will show up as they happen.
<Card variant="outlined" padding="md">
<h3 class="text-text-primary mb-3 text-sm font-semibold">Recent activity</h3>
<EmptyState
density="compact"
icon={SearchIcon}
title="Nothing here yet"
description="New events will show up as they happen."
/>
</Card>02 Customization
Pair with any icon from @urbicon-ui/blocks. Its round container is filled with
the neutral surface tokens, not the accent: an empty state is not the call to action —
the button under it is. On the page ground that fill reads as a faint wash, and inside an
elevated container — a Card, a Popover — it disappears,
because surface-subtle and surface-elevated are the same colour. Override
any slot with slotClasses, unstyled, or a preset.
For a fill that always reads, or for the accent back, pass slotClasses={{ iconWrapper: 'bg-primary-subtle text-primary-text' }}, or set it once for every empty state through the provider's defaults.EmptyState.slotClasses.iconWrapper.
Use the cta snippet for the primary action; render your own markup via children for richer empty states (e.g. tutorials, illustrations).
03 Accessibility
The icon is decorative
The decorative icon is hidden from screen readers via its built-in aria-hidden.
The title is an h3
The title renders as an <h3>, so it nests under your page's <h1> in the heading hierarchy.
04 API Reference
11 propsProp | Type | Default | Description | |
|---|---|---|---|---|
title required | string | — | Heading line. | |
children | Snippet | — | Optional richer content rendered below the description. | |
class | string | — | Extra classes merged onto the wrapper. | |
cta | Snippet | — | Action buttons rendered below the description. | |
density | compactdefault | 'default' | Visual density. compact is suitable for inline empty rows in tables
or cards; default for full-page empty states. | |
description | string | — | Supporting paragraph below the title. | |
icon | Component<IconProps> | — | Icon component rendered above the title. Pass any icon from
@urbicon-ui/blocks (or a compatible stroke icon). Its round container is
filled bg-surface-subtle text-text-tertiary — an empty state is not the
call to action, cta is. That fill reads as a faint wash on the page
ground and as nothing at all inside an elevated container (Card, Popover),
where surface-subtle and surface-elevated resolve to the same colour.
For a fill that always reads, or for the accent back, pass
slotClasses={{ iconWrapper: 'bg-primary-subtle text-primary-text' }}. | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ EmptyState: {...} }}>.
Prefer this over class overrides when the same look should be reused
across the project. | |
slotClasses | Partial<Record<EmptyStateSlots, string>> | — | Per-slot class overrides. Slots: base | iconWrapper | title | description | children | cta | |
unstyled | boolean | — | Remove all default tv classes. | |
...HTMLAttributes<HTMLDivElement> inherited | HTMLAttributes | — | HTML attributes (excluding: 'children' | 'title') |
05 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
EmptyStateProps | interface | props | 0 | — | |
IconProps | interface | props | 0 | — | |
EmptyStateSlots | type | variant | 0 | Slot names derived from the tv() config — single source of truth for slotClasses. | |
SlotNames | type | helper | 0 | Extracts the slot-name union from a slotted tv() config function — the
companion to VariantProps. The slot-mode overload returns
(props?) => { [K in keyof S]: SlotFn }, so keyof ReturnType<T> is exactly
the set of slot names a component declares in tv({ slots: … }).
Use it to type a component's slotClasses prop from the single source of
truth (its *.variants.ts) instead of hand-maintaining a parallel union
that silently drifts when a slot is added or renamed: |
06 Installation
Import
import { EmptyState, BuildingIcon } from '@urbicon-ui/blocks';