# EmptyState

> Package `@umriss-ui/core`, version 0.40.0. Demo page: <https://romanhaendler.github.io/umriss-ui/core/emptystate/>. Every page in one line: [llms.txt](https://romanhaendler.github.io/umriss-ui/core/llms.txt); every page in full: [llms-full.txt](https://romanhaendler.github.io/umriss-ui/core/llms-full.txt).

What stands where a list or panel has nothing to show: what is missing, why, and the way forward (also called a blank slate). Reach for it for a first use, a filter that found nothing, or a queue that is clear.

```ts
import { EmptyState } from "@umriss-ui/core";
```

Demo page: https://romanhaendler.github.io/umriss-ui/core/emptystate/

## Examples

### Nothing yet

The `title` says what is missing, the `description` what would bring it, and the `action` is the way there.

```tsx
import { Button, EmptyState } from "@umriss-ui/core";

export default function NothingYet() {
  return (
    <EmptyState
      title="No reports yet"
      description="Reports you save from the budget overview appear here."
      action={
        <Button variant="primary" size="sm">
          Open the budget overview
        </Button>
      }
    />
  );
}
```

### Say why a filter found nothing

When filters empty a list, name them in the `description` and offer to clear them – the data is there, the view hides it.

```tsx
import { useState } from "react";
import { Button, EmptyState, Stack, Tag, TagGroup, Text } from "@umriss-ui/core";

/** Today's shipments from East Gate depot. */
const SHIPMENTS = [
  { id: "SH-1042", customer: "Harlow Bakery", status: "delivered" },
  { id: "SH-1043", customer: "Pine & Oak Florist", status: "out for delivery" },
  { id: "SH-1044", customer: "Moreau Optics", status: "delivered" },
];

export default function AFilterFoundNothing() {
  const [filters, setFilters] = useState(["Failed attempt", "East Gate depot"]);
  const shown = filters.includes("Failed attempt") ? [] : SHIPMENTS;

  return (
    <Stack gap={3}>
      <TagGroup aria-label="Active filters">
        {filters.map((filter) => (
          <Tag key={filter} tone="accent" onRemove={() => setFilters((all) => all.filter((f) => f !== filter))}>
            {filter}
          </Tag>
        ))}
      </TagGroup>
      {shown.length === 0 ? (
        <EmptyState
          title="No shipments match these filters"
          description={`Nothing today matches ${filters.map((f) => `“${f}”`).join(" and ")}.`}
          action={
            <Button size="sm" onClick={() => setFilters([])}>
              Clear the filters
            </Button>
          }
        />
      ) : (
        shown.map((shipment) => (
          <Text key={shipment.id} size="sm">
            {shipment.id} · {shipment.customer} · {shipment.status}
          </Text>
        ))
      )}
    </Stack>
  );
}
```

### Mark good news in a panel

An empty panel can be the good case; an `icon` and a plain `title` say so, and no action is needed.

```tsx
import { Card, CardBody, CardHeader, EmptyState } from "@umriss-ui/core";

function Check() {
  return (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="1.5" />
      <path d="M7.5 12.5l3 3 6-6.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

export default function InAPanel() {
  return (
    <Card style={{ maxWidth: 420 }}>
      <CardHeader eyebrow="Identity" title="Open incidents" />
      <CardBody>
        <EmptyState
          icon={<Check />}
          title="No open incidents"
          description="The last one, INC-1045, was resolved yesterday at 15:05."
        />
      </CardBody>
    </Card>
  );
}
```

## When to use something else

- Something went wrong and the reader must act → Alert
- The content is still loading → Skeleton

## Keyboard

The keys of [Button](https://romanhaendler.github.io/umriss-ui/core/button/#keyboard-button) and [Tag](https://romanhaendler.github.io/umriss-ui/core/tag/#keyboard-tag) apply here.

## API

### `EmptyStateProps`

| Prop | Type | Default | Description |
|---|---|---|---|
| `title` *required* | `ReactNode` | — | What is missing here - as a statement, not as an apology.<br>Shown in: [Nothing yet](https://romanhaendler.github.io/umriss-ui/core/emptystate/#nothing-yet), [Say why a filter found nothing](https://romanhaendler.github.io/umriss-ui/core/emptystate/#a-filter-found-nothing), [Mark good news in a panel](https://romanhaendler.github.io/umriss-ui/core/emptystate/#in-a-panel) and 3 more |
| `description` | `ReactNode` | — | One sentence on why nothing is here and what would put something here.<br>Shown in: [Nothing yet](https://romanhaendler.github.io/umriss-ui/core/emptystate/#nothing-yet), [Say why a filter found nothing](https://romanhaendler.github.io/umriss-ui/core/emptystate/#a-filter-found-nothing), [Mark good news in a panel](https://romanhaendler.github.io/umriss-ui/core/emptystate/#in-a-panel) and 3 more |
| `action` | `ReactNode` | — | The way into the next action, e.g. a button.<br>Shown in: [Nothing yet](https://romanhaendler.github.io/umriss-ui/core/emptystate/#nothing-yet), [Say why a filter found nothing](https://romanhaendler.github.io/umriss-ui/core/emptystate/#a-filter-found-nothing), [Cards on a dashboard (Card)](https://romanhaendler.github.io/umriss-ui/core/card/#cards-on-a-dashboard) and 1 more |
| `icon` | `ReactNode` | — | Optional symbol above the title.<br>Shown in: [Mark good news in a panel](https://romanhaendler.github.io/umriss-ui/core/emptystate/#in-a-panel) |
| `ref` | `Ref<HTMLDivElement>` | — | Receives the component's root element. From `RefProp`.<br>Shown in: [A row that holds still (Sizes)](https://romanhaendler.github.io/umriss-ui/core/sizes/#a-row-that-holds-still), [An anchored surface (Popover)](https://romanhaendler.github.io/umriss-ui/core/popover/#anchored-surface), [Take the width of the trigger (Popover)](https://romanhaendler.github.io/umriss-ui/core/popover/#width-from-anchor) and 2 more |

Also takes every attribute of `<div>` – without `title`.
