Github

Empty

Display an empty state with media, text, and actions.

No Projects Yet
You haven't created any projects yet. Get started by creating your first project.
Learn More
import { ArrowUpRightIcon, FolderCode } from "lucide-react";
import { Button, buttonVariants } from "@/components/ui/button";
import {
	Empty,
	EmptyContent,
	EmptyDescription,
	EmptyHeader,
	EmptyMedia,
	EmptyTitle,
} from "@/components/ui/empty";

export function EmptyDemo() {
	return (
		<Empty>
			<EmptyHeader>
				<EmptyMedia variant="icon">
					<FolderCode />
				</EmptyMedia>
				<EmptyTitle>No Projects Yet</EmptyTitle>
				<EmptyDescription>
					You haven&apos;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>
			<a className={buttonVariants({ variant: "link", size: "sm" })} href="#">
				Learn More <ArrowUpRightIcon data-icon="inline-end" />
			</a>
		</Empty>
	);
}

Installation

pnpm dlx shadcn@latest add https://herocn.dev/r/empty.json

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

Examples

Outline

Use a dashed border to make an outlined empty state.

Cloud Storage Empty
Upload files to your cloud storage to access them anywhere.
import { Cloud } from "lucide-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">
					<Cloud />
				</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

Add a muted background for low-contrast states.

No Notifications
You're all caught up. New notifications will appear here.
import { Bell, RefreshCcwIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import {
	Empty,
	EmptyContent,
	EmptyDescription,
	EmptyHeader,
	EmptyMedia,
	EmptyTitle,
} from "@/components/ui/empty";

export function EmptyBackground() {
	return (
		<Empty className="h-full bg-muted/30">
			<EmptyHeader>
				<EmptyMedia variant="icon">
					<Bell />
				</EmptyMedia>
				<EmptyTitle>No Notifications</EmptyTitle>
				<EmptyDescription className="max-w-xs text-pretty">
					You&apos;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 EmptyMedia to render an avatar-based empty state.

LR
User Offline
This user is currently offline. You can leave a message to notify them or try again later.
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/Maqed.png" />
						<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

Show a group of avatars to indicate team or collaborator context.

MqdCNER
No Team Members
Invite your team to collaborate on this project.
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">
						<Avatar>
							<AvatarImage src="https://github.com/Maqed.png" alt="@0xMaqed" />
							<AvatarFallback>Mqd</AvatarFallback>
						</Avatar>
						<Avatar>
							<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
							<AvatarFallback>CN</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 data-icon="inline-start" />
					Invite Members
				</Button>
			</EmptyContent>
		</Empty>
	);
}

Input Group

Place interactive search or filter controls in EmptyContent.

404 - Not Found
The page you're looking for doesn't exist. Try searching for what you need below.
/
Need help? Contact support
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&apos;re looking for doesn&apos;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

لا توجد مشاريع بعد
لم تقم بإنشاء أي مشاريع بعد. ابدأ بإنشاء مشروعك الأول.
تعرف على المزيد
"use client";

import { ArrowUpRightIcon, FolderCode } from "lucide-react";

import {
	type Translations,
	useTranslation,
} from "@/components/language-selector";
import { Button } from "@/components/ui/button";
import {
	Empty,
	EmptyContent,
	EmptyDescription,
	EmptyHeader,
	EmptyMedia,
	EmptyTitle,
} from "@/components/ui/empty";

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, language, t } = useTranslation(translations, "ar");

	return (
		<div lang={language} dir={dir}>
			<Empty>
				<EmptyHeader>
					<EmptyMedia variant="icon">
						<FolderCode />
					</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>
		</div>
	);
}

API Reference

Empty

The root container for the empty state.

PropTypeDefault
classNamestring

EmptyHeader

Wraps the media, title, and description.

PropTypeDefault
classNamestring

EmptyMedia

Displays an icon, image, avatar, or any custom media.

PropTypeDefault
variant"default" | "icon"
"default"
classNamestring

EmptyTitle

The primary heading for the empty state.

PropTypeDefault
classNamestring

EmptyDescription

Secondary text that explains the empty state.

PropTypeDefault
classNamestring

EmptyContent

Action area for buttons, inputs, or links.

PropTypeDefault
classNamestring