EmptyState
A reusable empty-state block for lists, tables, cards, and no-results screens. Use it instead of bare “No data” strings. Every action supports primary/secondary styling, leading or trailing icons, and TanStack Router links.
Tweak props live and copy the generated JSX snippet.
<EmptyState
icon={<Inbox className="size-6" />}
title="No simulations yet"
description="Create your first sim from the Builder."
actions={[
{ label: "New simulation", icon: <Plus className="size-3.5" />, onClick: handleClick },
{ label: "Learn more", iconRight: <ArrowRight className="size-3.5" />, to: "/builder" },
]}
/>The URL updates as you tweak — copy and share to reproduce this exact config.
Live view of the validated pg* search params after Zod parsing and safe-fallback coercion. Tamper with the URL — any invalid value snaps back to its default here.
| Param | Type | Effective value |
|---|---|---|
| pgCompact | boolean | false |
| pgDesc | string | "Create your first sim from the Builder." |
| pgIcon | string | "Inbox" |
| pgP | boolean | true |
| pgPIcon | string | "Plus" |
| pgPIconR | string | "none" |
| pgPLabel | string | "New simulation" |
| pgPLink | boolean | false |
| pgPVariant | string | "auto" |
| pgS | boolean | true |
| pgSIcon | string | "none" |
| pgSIconR | string | "ArrowRight" |
| pgSLabel | string | "Learn more" |
| pgSLink | boolean | true |
| pgSVariant | string | "auto" |
| pgTitle | string | "No simulations yet" |
Wrap an empty screen in EmptyState. Provide title, an optional description, and one or more actions. The first action defaults to the primary button variant; subsequent actions default to outline.
<EmptyState
icon={<Inbox className="size-6" />}
title="No simulations yet"
description="Create your first sim from the Builder."
actions={[
{ label: "New simulation", icon: <Plus className="size-3.5" />, onClick: create },
{ label: "Learn more", iconRight: <ArrowRight className="size-3.5" />, to: "/docs" },
]}
/>Set variant on any action to override the default. The first action uses "default" (filled primary) unless you override it; every other action uses "outline". Supported variants come from the shadcn Button preset: default, secondary, outline, ghost, destructive, and link.
actions={[
{ label: "Create file", icon: <FilePlus className="size-3.5" />, onClick: create },
{ label: "Import", variant: "secondary", onClick: importFile },
{ label: "Learn more", variant: "ghost", iconRight: <ArrowRight className="size-3.5" />, to: "/docs" },
]}Pass icon to render a leading icon before the label. Icons are automatically marked aria-hidden="true" so they do not pollute the accessible name.
actions={[
{
label: "Clear filters",
icon: <RotateCcw className="size-3.5" />,
onClick: clearFilters,
},
]}Pass iconRight for a trailing icon after the label. This is useful for CTAs that imply navigation, such as “Go to docs” or “Browse templates”.
actions={[
{
label: "Go to docs",
iconRight: <ArrowRight className="size-3.5" />,
to: "/docs",
},
]}Use to instead of onClick to render a TanStack Link. The component renders a single <a> element (no nested button) so right-click/open-in-new-tab works naturally. The accessible name is derived from the label, ariaLabel, or title.
actions={[
{ label: "New simulation", icon: <Plus className="size-3.5" />, to: "/builder" },
{ label: "Browse templates", iconRight: <ArrowRight className="size-3.5" />, variant: "outline", to: "/templates" },
]}Add compact for tighter padding and smaller buttons. Use this inside panels, cards, or sidebars where the full empty-state treatment would feel heavy.
<EmptyState
compact
title="No alerts"
actions={[{ label: "Add", icon: <Plus className="size-3.5" />, onClick: addAlert }]}
/>| Prop | Type | Description |
|---|---|---|
| label | ReactNode | Visible button text. Used as the accessible name unless ariaLabel or title is provided. |
| icon | ReactNode | Optional leading icon (rendered before label). |
| iconRight | ReactNode | Optional trailing icon (rendered after label). |
| variant | Button variant | Overrides the default variant. First action is default; others are outline. |
| size | Button size | Optional size override. Compact mode defaults to sm. |
| onClick | () => void | Click handler. Mutually exclusive with to. |
| to | string | TanStack Router destination. Renders a Link. Mutually exclusive with onClick. |
| disabled | boolean | Disables the action and sets aria-disabled="true". |
| title | string | Tooltip / accessible-name fallback. |
| ariaLabel | string | Explicit accessible name. Required when label is non-textual. |
| ariaKeyShortcuts | string | Optional keyboard shortcut hint, surfaced via aria-keyshortcuts. |
| autoFocus | boolean | Focus this action on mount. Only the first true is honored. |
| id | string | Stable key for React reconciliation and testing. |
- The root element has
role="status",aria-live="polite", and is linked to the title and description viaaria-labelledby/aria-describedby. - Action buttons are wrapped in a
role="group"labelled “Suggested actions”. - Icons are
aria-hidden="true"; the accessible name comes from label, ariaLabel, or title. - Link actions render as a single
<a>(no nested button) so assistive tech reports the correct role and href. - Every action ships with a visible focus ring via
focus-visible:ring-2.