EmptyState

UI primitive used to represent valid empty states with clear messaging and optional actions.

The EmptyState component represents a valid state with no data.

It explains why there is nothing to display and optionally guides the user toward the next action — without introducing product or business logic.

EmptyState is a pure UI primitive: it structures content, nothing more.


Import

import { EmptyState } from "@/components/ui/empty-state";

Usage

Use EmptyState when a screen, section, or list has no content to display, but the application is otherwise in a valid state.

EmptyState should not be used for loading or error states.


Basic example

No projects yet

Create your first project to get started.

<EmptyState
  title="No projects yet"
  description="Create your first project to get started."
/>

With action

EmptyState can optionally render a primary action (button or link).

No projects yet

Projects help you organize your work.

import { EmptyState } from "@/components/ui/empty-state";
import { Button } from "@/components/ui/button";

export function EmptyStateWithAction() {
  return (
    <EmptyState
      title="No projects yet"
      description="Projects help you organize your work."
      action={<Button>Create project</Button>}
    />
  );
}

With icon

Use the icon slot for a simple decorative icon or illustration.

Nothing scheduled

Create an event to see it appear here.

<EmptyState
  icon={<CalendarIcon className="h-6 w-6" aria-hidden />}
  title="Nothing scheduled"
  description="Create an event to see it appear here."
  action={<Button variant="secondary">Create event</Button>}
/>

Inside a Card

EmptyState composes naturally with surfaces such as Card.

No data available

Metrics will appear once data is collected.

import { Card, CardContent } from "@/components/ui/card";
import { EmptyState } from "@/components/ui/empty-state";

export function CardEmptyState() {
  return (
    <Card>
      <CardContent className="p-6">
        <EmptyState
          title="No data available"
          description="Metrics will appear once data is collected."
        />
      </CardContent>
    </Card>
  );
}

Table empty state

EmptyState works well inside data-heavy components such as Table (especially for filtered results).

No results

Try adjusting your filters.

import { Table, TableBody, TableRow, TableCell } from "@/components/ui/table";
import { EmptyState } from "@/components/ui/empty-state";
import { Button } from "@/components/ui/button";

export function TableEmptyState() {
  return (
    <Table>
      <TableBody>
        <TableRow className="hover:bg-transparent">
          <TableCell colSpan={4} className="py-10">
            <EmptyState
              title="No results"
              description="Try adjusting your filters."
              action={
                <Button variant="outline" size="sm">
                  Clear filters
                </Button>
              }
            />
          </TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

API

Props

PropTypeRequiredDescription
titlestringYesPrimary message explaining the empty state
descriptionstringNoAdditional context for the empty state
actionReact.ReactNodeNoOptional action (button, link, etc.)
iconReact.ReactNodeNoOptional icon or illustration
classNamestringNoAdditional Tailwind classes

EmptyState also accepts all standard HTML div props:

React.HTMLAttributes<HTMLDivElement>

Accessibility

  • Rendered with role="status" to announce informational state changes.
  • Content remains readable without icons.
  • Actions are fully keyboard accessible.
  • No focus is forced when the empty state appears.
  • Avoid using EmptyState to announce errors (use Alert for that).

Design guidelines

  • Always explain why the state is empty (not just “Nothing here”).
  • Keep titles short and descriptive.
  • Use actions sparingly — one primary action is usually enough.
  • Avoid product-specific language inside the component; pages and patterns decide what happens next.
  • Keep the empty state aligned with surrounding density (use Card / Table wrappers as needed).

When not to use EmptyState

Do not use EmptyState for:

  • Loading states → use Skeleton
  • Error states → use Alert
  • Onboarding flows (use dedicated onboarding screens)
  • Blocking or modal interactions (use Dialog / Sheet patterns)