Data display
Empty state
An empty state turns "nothing here" into a next step. Say what is missing and why it matters, then offer one clear primary action and, if useful, a second one. Use the dashed variant for empty panels and drop zones, the small size inside cards, and a search-specific message when a filter finds nothing.
No invoices yet
Create your first invoice or import past ones from a CSV. Paid invoices show up in your reports automatically.
<EmptyState variant="dashed" icon={<FileText strokeWidth={1.75} />} title="No invoices yet" description="Create your first invoice or import past ones from a CSV. Paid invoices show up in your reports automatically." action={ <Button variant="primary" size="sm" iconLeft={<Plus strokeWidth={1.75} />}> Create invoice </Button> } secondaryAction={ <Button variant="secondary" size="sm" iconLeft={<Upload strokeWidth={1.75} />}> Import CSV </Button> }/>Usage
import { EmptyState } from "@/components/ui/empty-state"; <EmptyState icon={<FileText strokeWidth={1.75} />} title="No invoices yet" description="Create your first invoice to get paid." action={<Button variant="primary">Create invoice</Button>}/>Examples
Overview
No invoices yet
Create your first invoice or import past ones from a CSV. Paid invoices show up in your reports automatically.
<EmptyState variant="dashed" icon={<FileText strokeWidth={1.75} />} title="No invoices yet" description="Create your first invoice or import past ones from a CSV. Paid invoices show up in your reports automatically." action={ <Button variant="primary" size="sm" iconLeft={<Plus strokeWidth={1.75} />}> Create invoice </Button> } secondaryAction={ <Button variant="secondary" size="sm" iconLeft={<Upload strokeWidth={1.75} />}> Import CSV </Button> }/>Without actions
When there is nothing to do, say so kindly. "All caught up" is good news, not an error.
You’re all caught up
New requests from your team will appear here.
<EmptyState icon={<Inbox strokeWidth={1.75} />} title="You’re all caught up" description="New requests from your team will appear here."/>No search results
Repeat the query, suggest what to try instead and offer a way back.
No results for “copperleef”
Check the spelling, or search by invoice number or email instead.
<EmptyState icon={<SearchX strokeWidth={1.75} />} title="No results for “copperleef”" description="Check the spelling, or search by invoice number or email instead." action={<Button variant="secondary" size="sm">Clear search</Button>}/>Inside a card
The small size fits card bodies and side panels.
Team
People with access to Ledgerly
Just you so far
Invite teammates to share invoices and reports.
Alerts
Payment and sync notifications
No alerts
We'll let you know when something needs attention.
<Card> <CardHeader titleAs="h3" title="Team" description="People with access to Ledgerly" /> <EmptyState size="sm" icon={<Users strokeWidth={1.75} />} title="Just you so far" description="Invite teammates to share invoices and reports." action={<Button variant="secondary" size="sm">Invite people</Button>} /></Card>Props
titlerequiredstringdefault: —What is empty, in plain words.descriptionReactNodedefault: —Why it matters or what to do next.iconReactNodedefault: —Lucide icon in a small tile.actionReactNodedefault: —Primary next step, usually a primary Button.secondaryActionReactNodedefault: —Optional second step.variant"plain" | "dashed"default: "plain"Dashed frame for empty panels and drop zones.size"sm" | "md"default: "md"Compact spacing for cards and panels.titleAs"p" | "h2" | "h3" | "h4"default: "p"Make the title a heading when the empty state is the main content.childrenReactNodedefault: —Extra content under the actions, such as a help link.
Accessibility
- Content is read in order: title, description, then actions. The icon is decorative and hidden.
- When an empty state replaces a whole page or panel, set titleAs to a heading so it shows up in the outline.
- Use buttons for actions that change the page and links for navigation; label them with verbs ("Create invoice", not "Click here").
- After clearing a search from the empty state, return focus to the search field.