What to show when a list, table or page has nothing in it yet: a short explanation and the next step.
import { Button, EmptyState } from "@rdloom/react";
const FolderIcon = () => (
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
<path d="M2.75 5.5A1.5 1.5 0 0 1 4.25 4h3.4l1.6 1.75h6.5a1.5 1.5 0 0 1 1.5 1.5v6.75a1.5 1.5 0 0 1-1.5 1.5H4.25a1.5 1.5 0 0 1-1.5-1.5V5.5z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />
</svg>
);
export default function EmptyStateBasicExample() {
return (
<div className="w-[28rem] max-w-full">
<EmptyState icon={<FolderIcon />} title="No projects yet" description="Projects keep your files, tasks and people in one place. Create your first to get started.">
<Button>Create project</Button>
<Button variant="ghost">Import</Button>
</EmptyState>
</div>
);
}Installation
npx rdloom add empty-stateCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/empty-state.jsonWorks, but without upgrade tracking.
Usage
import { Button, EmptyState } from "@rdloom/react";
<div className="w-[28rem] max-w-full">
<EmptyState icon={<FolderIcon />} title="No projects yet" description="Projects keep your files, tasks and people in one place. Create your first to get started.">
<Button>Create project</Button>
<Button variant="ghost">Import</Button>
</EmptyState>
</div>No results
import { Button, EmptyState } from "@rdloom/react";
const SearchIcon = () => (
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
<circle cx="9" cy="9" r="5.75" stroke="currentColor" strokeWidth="1.5" />
<path d="M13.5 13.5L17 17" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
);
export default function EmptyStateNoResultsExample() {
return (
<div className="w-[28rem] max-w-full">
<EmptyState icon={<SearchIcon />} title="No results for “invoice”" description="Check the spelling or try a broader search.">
<Button variant="secondary">Clear search</Button>
</EmptyState>
</div>
);
}Compact
import { EmptyState } from "@rdloom/react";
export default function EmptyStateCompactExample() {
return (
<div className="w-72">
<EmptyState size="sm" headingLevel={4} title="No comments" description="Be the first to reply." />
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
titlerequiredShort headline, e.g. "No projects yet". | string | none |
descriptionOne or two sentences on why it is empty and what to do. | string | none |
iconOptional illustration or icon, shown above the title. Decorative: it is hidden from screen readers. | node | none |
childrenActions, usually one or two Buttons. | node | none |
headingLevelHeading level of the title, 2 to 6. | number | 3 |
sizesm for inside a card or table, md for a whole page or panel. | "sm" | "md" | "md" |
Accessibility
Role none, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
Not interactive.
Screen readers announce
- Read in order: title, description, then the actions
What your code must do
- The title is a real heading at the level you choose
- The icon is decorative (aria-hidden): the title and description carry the meaning
- Actions are ordinary buttons or links in the normal tab order
- It is not announced as an alert: it is the page's content, not an interruption
Guidelines
Use it when
- A first-run screen, an empty list or a search with no results
- Telling people the next step when there is no data
Avoid it when
- An error: use Alert
- Data that is loading: use Skeleton
Don't
- Only a picture with no words
- No next step
- Using it for errors
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-subtle--rd-color-border-default--rd-color-text-default--rd-color-text-muted--rd-radius-overlay