- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input OTP
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
- New Component
No messages yet
When you receive messages they'll appear here. Start a conversation to get going.
import { Inbox } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Empty, EmptyAction, EmptyDescription, EmptyIcon, EmptyTitle } from "@/components/ui/empty";
export const EmptyDemo = () => (
<Empty>
<EmptyIcon><Inbox /></EmptyIcon>
<EmptyTitle>No messages yet</EmptyTitle>
<EmptyDescription>When you receive messages they'll appear here. Start a conversation to get going.</EmptyDescription>
<EmptyAction><Button>New message</Button></EmptyAction>
</Empty>
);With multiple actions
Use EmptyAction with multiple buttons when there are two clear paths forward.
import { FolderOpen } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Empty,
EmptyAction,
EmptyDescription,
EmptyIcon,
EmptyTitle,
} from "@/components/ui/empty";
<Empty>
<EmptyIcon>
<FolderOpen />
</EmptyIcon>
<EmptyTitle>No projects found</EmptyTitle>
<EmptyDescription>
Create a project to organise your work, or import an existing one.
</EmptyDescription>
<EmptyAction>
<Button>Create project</Button>
<Button variant="outline">Import</Button>
</EmptyAction>
</Empty>Without icon
Skip EmptyIcon when the context is already clear — for example inside a table or list where a large icon would feel heavy.
import {
Empty,
EmptyAction,
EmptyDescription,
EmptyTitle,
} from "@/components/ui/empty";
import { Button } from "@/components/ui/button";
<Empty className="py-8">
<EmptyTitle>No results</EmptyTitle>
<EmptyDescription>
Try adjusting your filters or search terms.
</EmptyDescription>
<EmptyAction>
<Button variant="outline" size="sm">Clear filters</Button>
</EmptyAction>
</Empty>In a table
Drop Empty directly inside a TableCell spanning all columns.
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Empty, EmptyDescription, EmptyTitle } from "@/components/ui/empty";
import { SearchX } from "lucide-react";
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Status</TableHead>
<TableHead>Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell colSpan={3}>
<Empty className="py-8">
<EmptyIcon>
<SearchX />
</EmptyIcon>
<EmptyTitle>No results</EmptyTitle>
<EmptyDescription>Try a different search term.</EmptyDescription>
</Empty>
</TableCell>
</TableRow>
</TableBody>
</Table>Full page
For page-level empty states, let Empty fill the available space with className="min-h-[60vh]".
import { PackageOpen } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Empty,
EmptyAction,
EmptyDescription,
EmptyIcon,
EmptyTitle,
} from "@/components/ui/empty";
export default function OrdersPage() {
return (
<main className="container">
<h1 className="text-2xl font-semibold">Orders</h1>
<Empty className="min-h-[60vh]">
<EmptyIcon>
<PackageOpen />
</EmptyIcon>
<EmptyTitle>No orders yet</EmptyTitle>
<EmptyDescription>
Orders placed by your customers will appear here.
</EmptyDescription>
<EmptyAction>
<Button>Share your store</Button>
</EmptyAction>
</Empty>
</main>
);
}Props
Empty
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Override py-12 for tighter/looser contexts, or add min-h-* for full-page states |
EmptyIcon
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Override size-14 or the background colour |
Accepts any icon or image element as children. Icons without an explicit size-* class are auto-sized to size-6.
EmptyTitle
Renders as <h3>. Accepts all native h3 props.
EmptyDescription
Renders as <p> with max-w-xs text-muted-foreground. Accepts all native p props.
EmptyAction
A flex row wrapper for buttons. Pass one or two Button elements. Accepts all native div props.
Usage
import {
Empty,
EmptyAction,
EmptyDescription,
EmptyIcon,
EmptyTitle,
} from "@/components/ui/empty";
import { Button } from "@/components/ui/button";
import { Inbox } from "lucide-react";
<Empty>
<EmptyIcon>
<Inbox />
</EmptyIcon>
<EmptyTitle>No messages yet</EmptyTitle>
<EmptyDescription>
Start a conversation to get going.
</EmptyDescription>
<EmptyAction>
<Button>New message</Button>
</EmptyAction>
</Empty>Specs
# Mint — Empty Specs
## Component
- name: empty
- file: registry/mint/empty.tsx
- installs to: components/ui/empty.tsx
- dependencies: none
- registryDependencies: none
- GIN Design exclusive (not in shadcn/ui)
## What is it
A compound component for communicating the absence of content — used when a
list, table, or page has nothing to show. It structures an icon, title,
description, and action into a centred, vertically stacked layout. Use it
instead of a blank area whenever users need context and a clear next step.
Do not use it for loading or error states; prefer a Spinner or an alert for
those cases.
## Visual identity
Minimal and calm, with a soft mint tint. The icon sits in a rounded circle
using Mint's muted green wash that softens the emptiness without drawing
excessive attention. Typography is tight — semibold title with small muted
description — keeping the message focused. The gentle green tone carries
through consistently wherever Empty appears.
## Design tokens
--muted: oklch(0.96 0.02 155) / oklch(0.2 0.03 155) — EmptyIcon background
--muted-foreground: oklch(0.52 0.06 155) / oklch(0.6 0.06 155) — EmptyIcon icon colour and EmptyDescription text
## Sub-components
- Empty → root container; flex-col, items-center, justify-center, gap-3, py-12, text-center
- EmptyIcon → muted circle (size-14, rounded-full, bg-muted, text-muted-foreground); auto-sizes child SVGs to size-6
- EmptyTitle → h3; text-base font-semibold leading-none tracking-tight
- EmptyDescription → p; text-sm text-muted-foreground max-w-xs
- EmptyAction → div; mt-1 flex flex-wrap items-center justify-center gap-2; holds 1–2 Button elements
## Conventions
- Default vertical padding is py-12; override with className for tighter contexts (py-8 in tables) or full-page states (min-h-[60vh])
- Skip EmptyIcon in dense contexts such as table rows where a large icon adds visual noise
- EmptyTitle should be a noun phrase naming what is missing ("No messages yet")
- EmptyDescription should be 1–2 sentences explaining why and what to do next
- EmptyAction action labels should use an action verb matching the creation flow ("New message", "Create project")
- Avoid vague filler copy ("Oops! Nothing here.") — be specific and helpful
- Sub-components expose data-slot="empty", data-slot="empty-icon", data-slot="empty-title", data-slot="empty-description", and data-slot="empty-action" for CSS targetingInstallation
$ npx shadcn add \https://gin-design.vercel.app/empty