import { IconFolderCode } from "@tabler/icons-react"
import { ArrowUpRightIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
export function EmptyDemo() {
return (
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<IconFolderCode />
</EmptyMedia>
<EmptyTitle>No Projects Yet</EmptyTitle>
<EmptyDescription>
You haven't created any projects yet. Get started by creating
your first project.
</EmptyDescription>
</EmptyHeader>
<EmptyContent className="flex-row justify-center gap-2">
<Button>Create Project</Button>
<Button variant="outline">Import Project</Button>
</EmptyContent>
<Button
variant="link"
render={<a href="#" />}
className="text-muted-foreground"
size="sm"
nativeButton={false}
>
Learn More <ArrowUpRightIcon />
</Button>
</Empty>
)
}Installation
npx shadcn@latest add @fulldev/empty
Usage
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<Icon />
</EmptyMedia>
<EmptyTitle>No data</EmptyTitle>
<EmptyDescription>No data found</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>Add data</Button>
</EmptyContent>
</Empty>
Composition
Use the following composition to build an Empty state:
Empty
├── EmptyHeader
│ ├── EmptyMedia
│ ├── EmptyTitle
│ └── EmptyDescription
└── EmptyContent
Outline
Use the border utility class to create an outline empty state.
import { IconCloud } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
export function EmptyOutline() {
return (
<Empty className="border border-dashed">
<EmptyHeader>
<EmptyMedia variant="icon">
<IconCloud />
</EmptyMedia>
<EmptyTitle>Cloud Storage Empty</EmptyTitle>
<EmptyDescription>
Upload files to your cloud storage to access them anywhere.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button variant="outline" size="sm">
Upload Files
</Button>
</EmptyContent>
</Empty>
)
}Background
Use the bg-* and bg-gradient-* utilities to add a background to the empty state.
import { IconBell } from "@tabler/icons-react"
import { RefreshCcwIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
export function EmptyMuted() {
return (
<Empty className="h-full bg-muted/30">
<EmptyHeader>
<EmptyMedia variant="icon">
<IconBell />
</EmptyMedia>
<EmptyTitle>No Notifications</EmptyTitle>
<EmptyDescription className="max-w-xs text-pretty">
You're all caught up. New notifications will appear here.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button variant="outline">
<RefreshCcwIcon data-icon="inline-start" />
Refresh
</Button>
</EmptyContent>
</Empty>
)
}Avatar
Use the EmptyMedia component to display an avatar in the empty state.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
export function EmptyAvatar() {
return (
<Empty>
<EmptyHeader>
<EmptyMedia variant="default">
<Avatar className="size-12">
<AvatarImage
src="https://github.com/shadcn.png"
className="grayscale"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
</EmptyMedia>
<EmptyTitle>User Offline</EmptyTitle>
<EmptyDescription>
This user is currently offline. You can leave a message to notify them
or try again later.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button size="sm">Leave Message</Button>
</EmptyContent>
</Empty>
)
}Avatar Group
Use the EmptyMedia component to display an avatar group in the empty state.
import { PlusIcon } from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
export function EmptyAvatarGroup() {
return (
<Empty>
<EmptyHeader>
<EmptyMedia>
<div className="flex -space-x-2 *:data-[slot=avatar]:size-12 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background *:data-[slot=avatar]:grayscale">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://github.com/maxleiter.png"
alt="@maxleiter"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://github.com/evilrabbit.png"
alt="@evilrabbit"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
</div>
</EmptyMedia>
<EmptyTitle>No Team Members</EmptyTitle>
<EmptyDescription>
Invite your team to collaborate on this project.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button size="sm">
<PlusIcon />
Invite Members
</Button>
</EmptyContent>
</Empty>
)
}InputGroup
You can add an InputGroup component to the EmptyContent component.
import { SearchIcon } from "lucide-react"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyTitle,
} from "@/components/ui/empty"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"
import { Kbd } from "@/components/ui/kbd"
export function EmptyInputGroup() {
return (
<Empty>
<EmptyHeader>
<EmptyTitle>404 - Not Found</EmptyTitle>
<EmptyDescription>
The page you're looking for doesn't exist. Try searching for
what you need below.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<InputGroup className="sm:w-3/4">
<InputGroupInput placeholder="Try searching for pages..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<Kbd>/</Kbd>
</InputGroupAddon>
</InputGroup>
<EmptyDescription>
Need help? <a href="#">Contact support</a>
</EmptyDescription>
</EmptyContent>
</Empty>
)
}RTL
To enable RTL support in shadcn/ui, see the RTL configuration guide.
"use client"
import * as React from "react"
import { IconFolderCode } from "@tabler/icons-react"
import { ArrowUpRightIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
import {
useTranslation,
type Translations,
} from "@/components/language-selector"
const translations: Translations = {
en: {
dir: "ltr",
values: {
title: "No Projects Yet",
description:
"You haven't created any projects yet. Get started by creating your first project.",
createProject: "Create Project",
importProject: "Import Project",
learnMore: "Learn More",
},
},
ar: {
dir: "rtl",
values: {
title: "لا توجد مشاريع بعد",
description: "لم تقم بإنشاء أي مشاريع بعد. ابدأ بإنشاء مشروعك الأول.",
createProject: "إنشاء مشروع",
importProject: "استيراد مشروع",
learnMore: "تعرف على المزيد",
},
},
he: {
dir: "rtl",
values: {
title: "אין פרויקטים עדיין",
description:
"עדיין לא יצרת פרויקטים. התחל על ידי יצירת הפרויקט הראשון שלך.",
createProject: "צור פרויקט",
importProject: "ייבא פרויקט",
learnMore: "למד עוד",
},
},
}
export function EmptyRtl() {
const { dir, t } = useTranslation(translations, "ar")
return (
<Empty dir={dir}>
<EmptyHeader>
<EmptyMedia variant="icon">
<IconFolderCode />
</EmptyMedia>
<EmptyTitle>{t.title}</EmptyTitle>
<EmptyDescription>{t.description}</EmptyDescription>
</EmptyHeader>
<EmptyContent className="flex-row justify-center gap-2">
<Button>{t.createProject}</Button>
<Button variant="outline">{t.importProject}</Button>
</EmptyContent>
<Button
variant="link"
render={<a href="#" />}
className="text-muted-foreground"
size="sm"
nativeButton={false}
>
{t.learnMore}{" "}
<ArrowUpRightIcon className="rtl:rotate-270" data-icon="inline-end" />
</Button>
</Empty>
)
}API Reference
Source: react/src/components/ui/empty.tsx
Empty
The main component of the empty state.
| Prop | Type | Default |
|---|---|---|
className | string |
<Empty>
<EmptyHeader />
<EmptyContent />
</Empty>
EmptyHeader
The EmptyHeader component wraps the empty media, title, and description.
| Prop | Type | Default |
|---|---|---|
className | string |
<EmptyHeader>
<EmptyMedia />
<EmptyTitle />
<EmptyDescription />
</EmptyHeader>
EmptyMedia
Use the EmptyMedia component to display the media of the empty state such as an icon or an image.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "icon" | default |
className | string |
<EmptyMedia variant="icon">
<Icon />
</EmptyMedia>
<EmptyMedia>
<Avatar>
<AvatarImage src="..." />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</EmptyMedia>
EmptyTitle
Use the EmptyTitle component to display the title of the empty state.
| Prop | Type | Default |
|---|---|---|
className | string |
<EmptyTitle>No data</EmptyTitle>
EmptyDescription
Use the EmptyDescription component to display the description of the empty state.
| Prop | Type | Default |
|---|---|---|
className | string |
<EmptyDescription>You do not have any notifications.</EmptyDescription>
EmptyContent
Use the EmptyContent component to display the content of the empty state such as a button, input or a link.
| Prop | Type | Default |
|---|---|---|
className | string |
<EmptyContent>
<Button>Add Project</Button>
</EmptyContent>