Skip to content
Nana UI

Feedback & Status

Empty State

A placeholder for a region that has nothing to show — an unfilled list, a search with no matches, a feature not set up yet. Pairs a glyph with a short heading, an explanation and the action that resolves it.

View .md Download
Invoices you create will show up here. New invoice

The empty state ships for all three targets. Pick the tab for your project — the CLI detects which you are on and serves the matching implementation.

npx @nana-tec/ui add empty-state

Lands as src/components/ui/empty-state/empty-state.tsx, styled with Tailwind classes that resolve to the design tokens. Requires Tailwind v4.

import { EmptyState } from "@/components/ui/empty-state";
import { Button } from "@/components/ui/button";
export function Example() {
return (
<EmptyState title="No invoices yet" actions={<Button size="sm">New invoice</Button>}>
Invoices you create will show up here.
</EmptyState>
);
}

title, icon and actions take nodes; the body copy is the children. A node passed to icon replaces the default glyph, and noIcon drops it:

<EmptyState icon={<SearchIcon />} title="No results" size="sm" bordered>
Nothing matched “quarterly”.
</EmptyState>

Classes you pass to the React and Svelte components are merged with tailwind-merge, so an override wins rather than fighting. See Using Tailwind.

size scales the glyph, the type and the padding together — sm for a panel or a popover, md for a card or a table body, lg for a page with nothing on it yet.

Compact panels and popovers. A card or a table body. A whole page with nothing in it yet.

A search that matched nothing is the most common empty state, and it reads better with the query in the copy and a way back out of it.

Nothing matched “quarterly”. Try a broader term or clear the filters. Clear filters

Anything in the icon slot replaces the bundled glyph — another icon set, a small illustration, a logo.

Items you archive are kept here for 30 days.

Table has its own empty slot for the placeholder that spans the columns. Drop an empty state into it so the message matches the rest of the app.

Invoice Customer Amount Invoices you create will show up here.

Select and Combobox both expose an empty slot for the message their panel shows when nothing is left to pick. Slot an empty state in and the panel drops its own padding so the two do not stack.

<nana-combobox label="Country" placeholder="Type to filter…">
<nana-option value="ke">Kenya</nana-option>
<nana-empty-state slot="empty" size="sm" icon="search" title="No countries">
Nothing matched that search.
</nana-empty-state>
</nana-combobox>

The host takes role="status" and aria-live="polite" unless you set a role yourself, so a screen reader hears the placeholder when it replaces content that has just finished loading. Set role="region" with an aria-label instead when the block is part of the page from the start and should not announce itself.

The glyph is decorative — it is marked aria-hidden, so the heading and body copy have to carry the meaning on their own.

The React and Svelte props, read from the components’ own types:

EmptyState

PropTypeDefault
sizeEmptyStateSize'md'
titleReactNode
icon
A node replaces the default glyph; `noIcon` drops it entirely.
ReactNode
noIconbooleanfalse
actionsReactNode
bordered
Draw a dashed placeholder box around the block.
booleanfalse
childrenReactNode

Also accepts Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'children'>.

The attribute names and CSS hooks below are the Web Components reference.

Properties

PropertyAttributeTypeDefaultDescription
borderedborderedbooleanfalseDraw a dashed placeholder box around the block
iconiconstring'inbox'Name of a bundled icon to use as the glyph
noIconno-iconbooleanfalseHide the glyph
sizesizeEmptyStateSize'md'Scale of the whole block — glyph, type and padding together
titletitlestring''Bold heading shown under the glyph

Slots

SlotDescription
(default)The explanatory body copy
iconCustom glyph or illustration (overrides the default icon)
actionsButtons that resolve the empty state

CSS parts

PartDescription
::part(actions)The actions area
::part(base)The empty-state container
::part(description)The body copy
::part(icon)The leading glyph
::part(title)The heading line

CSS custom properties

PropertyDescription
--nana-empty-state-bgCustom background colour
--nana-empty-state-colorCustom text colour
--nana-empty-state-borderCustom border colour, when bordered
--nana-empty-state-icon-colorCustom glyph colour
--nana-empty-state-glyph-sizeCustom glyph box size, overriding size
SlotDescription
(default)The explanatory body copy
iconCustom glyph or illustration (overrides the default icon)
actionsButtons that resolve the empty state
VariableDefaultDescription
--nana-empty-state-bgtransparentCustom background colour
--nana-empty-state-color—Custom text colour
--nana-empty-state-border—Custom border colour, when bordered
--nana-empty-state-icon-color—Custom glyph colour
--nana-empty-state-glyph-size2.5remCustom glyph box size, overriding size
PartDescription
baseThe empty-state container
iconThe leading glyph
titleThe heading line
descriptionThe body copy
actionsThe actions area
Explore Empty State interactively Every state, prop, and edge case — with live controls — in Storybook.
View in Storybook