# Empty state

Package: @commenda/pathfinder@0.1.0
Page: /docs/components/empty-state
Figma: https://www.figma.com/design/dn7BkGYEfIyP0o2zfesfVh/The-System?node-id=331-2

```tsx
import { EmptyState } from '@commenda/pathfinder/empty-state';
<EmptyState
  headingLevel={2}
  kind="first-use"
  title="No filings yet"
  description="Filings you create, or that we prepare for you, show up here."
  primaryAction={{ label: 'Create filing', onClick: onCreateFiling }}
/>;
```


## Installation [#installation]

```sh
pnpm --filter your-app add "@commenda/pathfinder@workspace:*"
```

Import `@commenda/pathfinder/styles.css` once after host CSS. Styles are precompiled with Tailwind v4; consumers need no Tailwind scanning. Interactive callbacks belong in client components in Next.js App Router.

## Usage [#usage]

```tsx
import { EmptyState } from '@commenda/pathfinder/empty-state';
<EmptyState
  kind="first-use"
  title="No filings yet"
  description="Filings you create, or that we prepare for you, show up here."
  primaryAction={{ label: 'Create filing', onClick: onCreateFiling }}
/>;
```

## API reference [#api-reference]

| Prop | Type | Requirement | Behavior |
| --- | --- | --- | --- |
| `kind` | `"error" \| "first-use" \| "no-results" \| "all-done" \| "no-access"` | required | Required |
| `title` | `string` | required | Required, sentence case |
| `description` | `string` | optional | Optional supporting explanation |
| `size` | `"section" \| "page"` | optional | section; 32 / 64 px vertical padding |
| `headingLevel` | `2 \| 3 \| 4` | optional | 3 |
| `primaryAction` | `FeedbackAction` | optional | Second only for a genuine alternate path |
| `secondaryAction` | `FeedbackAction` | optional | Second only for a genuine alternate path |
| `referenceId` | `string` | optional | Only available for kind="error" |
| `className` | `string` | optional | Parent layout customization |

Replace the table body, card or content region, rather than leaving an empty table beside the message. First-use invites creation, no-results offers a way back, no-access explains who can grant access, and error offers retry. Use Skeleton until loading completes. The caller owns retry/loading, subsequent content replacement and focus. Page size fills its parent, not the viewport. The source prototype’s 1.2-second delay is not production behavior.

### Actions [#actions]

`FeedbackAction` requires a label and exactly one of `onClick` (command) or `href` (native navigation). Commands support `disabled`, `disabledReason`, `loadingConfig`, and `leadingIcon`; navigation supports `target`, `rel`, and `leadingIcon`. The application owns async work and retry state.

## Examples [#examples]

### Kinds [#kinds]


```tsx
<>
  <EmptyState
    headingLevel={2}
    kind="first-use"
    title="No filings yet"
    description="Filings you create, or that we prepare for you, show up here."
    primaryAction={{ label: 'Create filing', onClick: onAction }}
  />
  <EmptyState
    headingLevel={2}
    kind="no-results"
    title="No results for “Delaware 2027”"
    description="Try a different search, or clear the filters."
    primaryAction={{ label: 'Clear filters', onClick: onAction }}
  />
  <EmptyState
    headingLevel={2}
    kind="all-done"
    title="You’re all caught up"
    description="No tasks need you right now. New ones show up here."
    primaryAction={{ label: 'View completed', onClick: onAction }}
  />
  <EmptyState
    headingLevel={2}
    kind="no-access"
    title="You don’t have access"
    description="Ask an admin to give you access to Transfer pricing."
    primaryAction={{ label: 'Request access', onClick: onAction }}
  />
  <EmptyState
    headingLevel={2}
    kind="error"
    referenceId="EXP-42"
    title="Could not load filings"
    description="Check your connection and try again."
    primaryAction={{ label: 'Try again', onClick: onAction }}
  />
</>;
```


### Page [#page]


```tsx
import { EmptyState } from '@commenda/pathfinder/empty-state';
<EmptyState
  headingLevel={2}
  kind="first-use"
  size="page"
  title="No filings yet"
  description="Filings you create, or that we prepare for you, show up here."
  primaryAction={{ label: 'Create filing', onClick: onCreateFiling }}
/>;
```


Read the [design guidance](/docs/components/empty-state#design-rules) before using these components.

## Design rules [#design-rules]

Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.

### Empty state — 331:2 [#empty-state--3312]

- **EMPTY-01:** Replace the content region with an explanation of why it is empty and what fills it. Do not place the message beside an empty table. First-use invites creation; no-results names the search when possible and offers a way back; all-done acknowledges completion; no-access explains who grants access; error explains failure and offers retry.
- **EMPTY-02:** Sentence-case title without a period, description in one or two concise lines. One useful action, a second only for a genuine alternative. Show error references only where support uses them; never display a raw error code alone. Skeleton remains until loading has actually completed.
- **EMPTY-03:** Plain neutral 24 px source icon; no illustration or featured circle. Heading/15 title, Copy/13 description with 400 px max width; gap 12, text gap 4, actions gap 8/padding-top 4. Horizontal padding 24; page vertical 64, section vertical 32. Page fills the parent content region, not the viewport.
- **EMPTY-04:** Application owns retry/loading and replacement content. Preserve focus and layout when content arrives. The source prototype's 1.2-second timer illustrates an asynchronous request and is not a production default.
