Basel Standard / Docs
Empty
Structured empty-state surface for filters, first-run flows, and data views with no available results.
Adjust the search scope or clear one of the active filters to restore the archive.
Empty states explain why content is missing and what the user can do next. The Swiss version keeps the frame, header, and action row explicit so an empty result reads like part of the product surface, not like a leftover placeholder.
Installation
Purchase access, then open /account/install to issue a registry token.Usage
import {
Empty,
EmptyActions,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
<Empty>
<EmptyHeader>
<EmptyMedia>{/* icon or status mark */}</EmptyMedia>
<EmptyTitle>No matching releases</EmptyTitle>
<EmptyDescription>
Clear a filter or widen the search to restore the archive.
</EmptyDescription>
</EmptyHeader>
<EmptyActions>{/* buttons or links */}</EmptyActions>
</Empty>
Why This Primitive Exists
A useful empty state does two jobs at once: it names the absence clearly and preserves the surrounding layout rhythm.
- Use it when a list, table, or workspace has no content to show.
- Use it for first-run states when the user still needs orientation before the first action.
- Avoid it when a lightweight inline message will do; not every blank area needs a full framed state.
Examples
Basic Empty State
The default composition is enough for most filtered views: one signal, one title, one short explanation, and a small action row.
Adjust the search scope or clear one of the active filters to restore the archive.
<Empty>
<EmptyHeader>
<EmptyTitle>No matching releases</EmptyTitle>
<EmptyDescription>
Adjust the search scope or clear one of the active filters.
</EmptyDescription>
</EmptyHeader>
<EmptyActions>
<Button>Clear filters</Button>
</EmptyActions>
</Empty>
First-Run Actions
When the state is empty because the workspace has not started yet, the actions matter as much as the explanation.
Start the workspace with one source document, then invite the team after the structure is in place.
<EmptyActions>
<Button>Add first document</Button>
<Button variant="outline">Import from drive</Button>
</EmptyActions>
In Context
Keep the empty state inside the same card, table, or results surface that lost its content. That keeps the interruption local and easier to interpret.
Results state
The current filters exclude archived vendors and entries below the selected threshold.
<CardContent>
<Empty className="min-h-64">
<EmptyHeader>{/* state copy */}</EmptyHeader>
<EmptyActions>{/* recovery actions */}</EmptyActions>
</Empty>
</CardContent>
Guidance
Name The Absence Precisely
- Say what is missing: results, invoices, files, approvals.
- Use the description to explain the likely cause, not to repeat the title.
- Keep the body short enough to scan before the next action.
Keep Actions Limited
- Prefer one primary recovery action.
- Add a secondary action only if it changes the path meaningfully.
- Avoid turning the empty state into a control panel with five competing buttons.
Let The Surrounding Surface Provide Context
- Keep the state inside the table, card, or panel that became empty.
- Match the empty-state copy to the workflow language already used on the page.
- If the absence is temporary because data is still arriving, use a loading or skeleton state instead.
API Reference
Exports
| Export | Renders | Notes |
|---|---|---|
Empty | div | Outer container with centered grid layout and dashed border treatment. |
EmptyHeader | div | Groups media, title, and description. |
EmptyMedia | div | Fixed-size slot for an icon, badge, or simple visual marker. |
EmptyTitle | div | Uppercase heading for the primary message. |
EmptyDescription | p | Supporting explanation with the shared muted copy style. |
EmptyActions | div | Flex row for buttons, links, or follow-up actions. |
Empty
Empty accepts the full React.ComponentProps<"div"> API.
| Prop | Type | Default |
|---|---|---|
className | string | undefined |
The remaining exports are also thin div or p wrappers, so standard props like id, aria-*, data-*, and children pass through unchanged.