Empty
A centered placeholder for states with nothing to show. Composes a media slot, title, description and an area for actions.
Playground
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<FileText />
</EmptyMedia>
<EmptyTitle>No documents</EmptyTitle>
<EmptyDescription>
Upload a document or create one from a template.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button size="sm">
<Plus />
New document
</Button>
</EmptyContent>
</Empty>Preview
Stack EmptyMedia, EmptyTitle and EmptyDescription inside an EmptyHeader, then put calls to action in EmptyContent.
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<FileText />
</EmptyMedia>
<EmptyTitle>No documents</EmptyTitle>
<EmptyDescription>
Upload a document or create one from a template.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button size="sm">
<Plus />
New document
</Button>
</EmptyContent>
</Empty>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/empty.jsonUsage
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"<Empty>
<EmptyHeader>
<EmptyTitle>No projects yet</EmptyTitle>
<EmptyDescription>
Create your first project to get started.
</EmptyDescription>
</EmptyHeader>
</Empty>Media variants
EmptyMedia takes a variant: icon renders a small muted tile that auto-sizes an svg child, while the default variant is an unstyled slot for larger artwork – illustrations, avatars or avatar groups.
<EmptyMedia variant="icon">
<Inbox />
</EmptyMedia>
<EmptyMedia>
<div className="flex size-16 items-center justify-center rounded-full bg-muted">
<Inbox className="size-8 text-muted-foreground" />
</div>
</EmptyMedia>With actions
EmptyContent centers whatever follows the header – pair a primary and a secondary button, or drop in a search input for no-results states.
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<Users />
</EmptyMedia>
<EmptyTitle>No teammates yet</EmptyTitle>
<EmptyDescription>
Invite people to collaborate on this workspace.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<div className="flex items-center gap-2">
<Button size="sm">
<Plus />
Invite
</Button>
<Button variant="outline" size="sm">
Learn more
<ArrowRight />
</Button>
</div>
</EmptyContent>
</Empty>No results
For filtered views, pair a Search icon tile with a search input in EmptyContent; links inside EmptyDescription are underlined automatically.
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<Search />
</EmptyMedia>
<EmptyTitle>No results found</EmptyTitle>
<EmptyDescription>
Try adjusting your search or filter to find what you are looking for.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<InputGroup>
<InputGroupAddon>
<Search />
</InputGroupAddon>
<InputGroupInput placeholder="Search again..." />
</InputGroup>
</EmptyContent>
</Empty>API reference
All parts render plain divs and accept className plus standard div props – only EmptyMedia has a variant. The root draws a dashed rounded border by default; override it with className (e.g. border-solid or border-none) to match the surrounding surface.
EmptyMedia
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "icon" | "default" | icon renders a size-7 muted rounded tile that auto-sizes an svg child to size-4; default is a transparent free-form slot. |
| Component | Description |
|---|---|
| Empty | Centered flex container (data-slot="empty") with a dashed border, rounded corners and balanced text. |
| EmptyHeader | Vertical stack for media, title and description (data-slot="empty-header"). |
| EmptyMedia | Media slot above the title (data-slot="empty-icon"), reflecting its variant as data-variant. |
| EmptyTitle | Medium-weight heading line (data-slot="empty-title"). |
| EmptyDescription | Muted supporting copy (data-slot="empty-description") with underlined links that highlight on hover. |
| EmptyContent | Centered action area below the header (data-slot="empty-content") for buttons, inputs or custom content. |
Styling hooks
Every part exposes a data-slot attribute (empty, empty-header, empty-icon, empty-title, empty-description, empty-content) and EmptyMedia also reflects data-variant – target these from CSS for app-level overrides. The component is purely presentational, so give the surrounding region an accessible name or status role if the empty state should be announced.