UIUpdated April 28, 2026

EmptyState

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

UIEmptyState

Explain valid absenceLink to section

The EmptyState component represents a valid state where there is no data to display.

Use it when:

  • a list has no items
  • a table has no results
  • a dashboard has no data yet
  • filters return nothing
  • a feature has not been configured
  • a user has not created their first object

EmptyState explains what happened and can guide the user toward the next action.

It is a pure UI primitive: it structures content, not product or business logic.

Core idea

Empty is not failure. EmptyState explains a valid absence and helps the user move forward.

ImportLink to section

empty-state-import.tsx
import { EmptyState } from "@pycolors/ui";

Basic usageLink to section

Use EmptyState when the application is in a valid state, but there is no content yet.

No projects yet

Create your first project to get started.

basic-empty-state.tsx
import { EmptyState } from "@pycolors/ui";

export function BasicEmptyState() {
  return (
    <EmptyState
      title="No projects yet"
      description="Create your first project to get started."
    />
  );
}

When to use EmptyStateLink to section

Use EmptyState when the request succeeded or the current state is valid, but the result is empty.

First-run states

Use when the user has not created projects, members, records, or resources yet.

Filtered results

Use when filters, search, or query constraints return no matching data.

Product surfaces

Use in dashboards, tables, cards, panels, and feature sections.

With actionLink to section

Use an action when there is a clear next step.

No projects yet

Projects help you organize your work.

empty-state-with-action.tsx
import { Button, EmptyState } from "@pycolors/ui";

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

Action rule

One clear action is usually enough. Empty states should guide users, not overwhelm them.

With iconLink to section

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

Nothing scheduled

Create an event to see it appear here.

empty-state-with-icon.tsx
import { Button, EmptyState } from "@pycolors/ui";
import { CalendarDays } from "lucide-react";

export function EmptyStateWithIcon() {
  return (
    <EmptyState
      icon={<CalendarDays className="h-6 w-6" aria-hidden="true" />}
      title="Nothing scheduled"
      description="Create an event to see it appear here."
      action={<Button variant="secondary">Create event</Button>}
    />
  );
}

Inside a CardLink to section

EmptyState composes naturally with surfaces such as Card.

No data available

Metrics will appear once data is collected.

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

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 stateLink to section

Use EmptyState inside a table when a query succeeds but returns no rows.

No results

Try adjusting your filters.

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

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 size="sm">
                  Clear filters
                </Button>
              }
            />
          </TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Usage patternsLink to section

Confirm the state is validLink to section

Use EmptyState only when the request succeeded or the absence is expected.

Explain why it is emptyLink to section

The title should name the state. The description should explain what it means.

Offer the next step when usefulLink to section

Add one action when the user can create, invite, reset filters, or configure something.

Match the surrounding surfaceLink to section

Use EmptyState inside Card, Table, or a section depending on the page structure.

Keep product logic outsideLink to section

EmptyState does not decide what happens next. The page or feature owns that behavior.

EmptyState vs Skeleton vs AlertLink to section

SituationUse
Data is loadingSkeleton
Request succeeded but there is no dataEmptyState
Request failedAlert
User must confirm an actionDialog
User needs a side workflowSheet
Onboarding requires several stepsDedicated onboarding UI

Decision rule

EmptyState explains valid absence. Skeleton represents loading. Alert communicates failure.

APILink to section

Props

PropTypeRequiredDescription
titlestringYesPrimary message explaining the empty state
descriptionstringNoAdditional context for the empty state
actionReact.ReactNodeNoOptional action
iconReact.ReactNodeNoOptional decorative icon or illustration
classNamestringNoAdditional Tailwind classes

EmptyState also accepts standard HTML div props.

empty-state-props.ts
React.HTMLAttributes<HTMLDivElement>

TypeScript typesLink to section

empty-state-types.ts
export interface EmptyStateProps
  extends React.HTMLAttributes<HTMLDivElement> {
  title: string;
  description?: string;
  action?: React.ReactNode;
  icon?: React.ReactNode;
}

AccessibilityLink to section

EmptyState should be readable and understandable without relying on icons.

Guidelines:

  • keep the title clear and descriptive
  • keep icon-only meaning out of the icon
  • mark decorative icons with aria-hidden="true"
  • do not force focus when an empty state appears
  • actions should be keyboard accessible
  • do not use EmptyState to announce errors
  • use Alert for failures and blocking problems

Accessibility rule

Empty states should explain themselves through text. Icons can support the message, but they should not carry the meaning alone.

Prefer / avoidLink to section

Prefer

  • clear title and short description
  • one useful action when appropriate
  • different copy for first-run and filtered-empty states
  • icons as supportive decoration
  • consistent placement inside Card or Table surfaces

Avoid

  • using EmptyState for errors
  • using EmptyState while data is still loading
  • vague titles like “Nothing here”
  • multiple competing actions
  • business logic inside the component

Product copy guidelinesLink to section

Empty state copy should answer two questions:

  1. Why is this empty?
  2. What can the user do next?

No projects yet

Create your first project to organize your work.

No results found

Try adjusting your filters or clearing the current search.

No metrics available

Metrics will appear once your app starts receiving data.

Common questionsLink to section

Next step

Ready to go further?

Move from documentation to a real production setup with authentication, billing, and backend foundations already wired.

Was this helpful?