A calm placeholder with an icon, explanation and a next action.
Keep your ideas, files and collaborators together.
pnpm dlx shadcn@latest add @latheui/empty-stateFirst time? Run npx latheui init once to add the @latheui registry. The CLI then writes the source into your project and installs what it needs. Or add it by hand:
Install the npm dependencies.
pnpm add lucide-reactCopy the source into your project.
"use client"
import * as React from "react"
import { FolderOpenIcon } from "lucide-react"
import { cn } from "@/lib/utils"
export type EmptyStateProps = Omit<React.ComponentProps<"div">, "title"> & {
title: string
description?: string
icon?: React.ReactNode
action?: React.ReactNode
headingLevel?: 2 | 3 | 4 | 5 | 6
}
export function EmptyState({
title,
description,
icon,
action,
headingLevel = 2,
className,
...props
}: EmptyStateProps) {
const Heading = ("h" + headingLevel) as "h2" | "h3" | "h4" | "h5" | "h6"
return (
<div
className={cn(
"flex flex-col items-center rounded-lg border border-dashed border-border bg-muted/20 px-6 py-10 text-center",
className
)}
{...props}
>
<div
aria-hidden="true"
className="mb-4 grid size-10 place-items-center rounded-lg border border-border bg-card text-muted-foreground"
>
{icon ?? <FolderOpenIcon className="size-5" />}
</div>
<Heading className="text-sm font-medium">{title}</Heading>
{description && (
<p className="mt-1.5 max-w-xs text-sm text-pretty text-muted-foreground">
{description}
</p>
)}
{action && <div className="mt-5">{action}</div>}
</div>
)
}Depends on
| Prop | Type | Default | Description |
|---|---|---|---|
| title* (required) | string | — | Short empty-state heading. |
| description | string | — | Explain the state and next step. |
| icon / action | ReactNode | — | Decorative icon and a meaningful action. |
Combine the control with your own layout. Semantic colors follow the active theme.
import * as React from "react"
import { EmptyState } from "@/components/ui/empty-state"
import { Button } from "@/components/ui/button"
export default function Demo(){const [created,setCreated]=React.useState(false);return <div className="w-full max-w-md">{created?<EmptyState title="Your first project is ready" description="A fresh canvas for your next idea." action={<Button variant="outline" size="sm" onClick={()=>setCreated(false)}>Reset preview</Button>}/>:<EmptyState title="Room for something new" description="Keep your ideas, files and collaborators together." action={<Button size="sm" onClick={()=>setCreated(true)}>Create a project</Button>}/>}</div>}