Empty State
The zero-data surface for lists, tables, searches, and inboxes: a debossed well where content will appear, with an optional icon key, copy, and actions.
No projects yet
Projects keep your team's work in one place. Create your first one to get started.
tsx
import { FolderPlus } from "lucide-react"
import { Button } from "@/registry/seam/ui/button"
import {
EmptyState,
EmptyStateActions,
EmptyStateDescription,
EmptyStateMedia,
EmptyStateTitle,
} from "@/registry/seam/ui/empty-state"
export default function EmptyStateDemo() {
return (
<EmptyState className="max-w-md">
<EmptyStateMedia>
<FolderPlus />
</EmptyStateMedia>
<EmptyStateTitle>No projects yet</EmptyStateTitle>
<EmptyStateDescription>
Projects keep your team's work in one place. Create your first one
to get started.
</EmptyStateDescription>
<EmptyStateActions>
<Button>New project</Button>
<Button variant="ghost">Import</Button>
</EmptyStateActions>
</EmptyState>
)
}bunx --bun @seamui/cli@latest add empty-stateAPI
| Prop | Type | Default | Description |
|---|---|---|---|
| — | composition | — | EmptyState wraps optional EmptyStateMedia (icon key), EmptyStateTitle, EmptyStateDescription, and EmptyStateActions. |
All parts are plain divs taking standard props — put seam Buttons in EmptyStateActions.
Notes
- A slot awaiting content reads as carved into the surface — the well is debossed (
shadow-well), and the icon rises from it on a small embossed key. The same one idea as inputs and tabs (§1). - Deliberately still: persistent page state gets no entrance motion. The action Buttons bring their own press depth and haptics.
- Pairs with the AI suite too — an empty conversation list or a no-sources answer uses the same shape.
Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.