<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Empty

What a list, search or page shows when it has nothing in it: an icon, a title that says what is empty, a sentence on what to do, and the action that does it.

```tsx
import { Empty } from "@/components/ouro/empty/empty";
```

## Example

```tsx
<Empty
  icon={<BookIcon />}
  title="No recipes yet"
  description="Start by creating your first recipe."
  action={<Button href="/recipes/new">Create recipe</Button>}
/>
```

## Use instead when

- Use `Alert` instead for an error or a warning, and `Skeleton` while the content is still loading.

## Props

Type: `EmptyProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `action` | `ReactNode` |  | The way out, usually one `Button`: `action={<Button href="/recipes/new">Create recipe</Button>}`. |
| `align` | `"start" \| "center"` | `"center"` | `center` centers everything, for a page or panel; `start` lines it up with the text around it. |
| `children` | `ReactNode` |  | Anything else under the description, such as a search field. |
| `className` | `string` |  | Layout only: margins, width, grid placement (`mt-6`). Appearance classes warn in development; use `variant`. |
| `description` | `ReactNode` |  | What the person can do about it, in a sentence: "Start by creating your first recipe." |
| `headingLevel` | `2 \| 3 \| 4 \| 5 \| 6` | `3` | The title's heading level. Pick the level below the section the Empty sits in. |
| `icon` | `ReactNode` |  | A decorative icon above the title, in a muted circle. Hidden from screen readers. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |
| `title` (required) | `string` |  | What is empty, as a short heading: "No recipes yet". Required, because it is what a screen reader finds. |
| `variant` | `"outline" \| "plain"` | `"outline"` | `outline` draws a dashed border around the empty area; `plain` has none, for an Empty inside a `Card` or a list that already has an edge. |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `actions`: Not a prop. Ouro UI uses `action`, one slot: `<Empty action={<Button>Add</Button>}>`.
- `heading`: Not a prop. Ouro UI uses `title`: `<Empty title="No recipes yet">`.
- `image`: Not a prop. Ouro UI uses `icon`: `<Empty icon={<Icon />}>`.
- `message`: Not a prop. Ouro UI uses `description`: `<Empty description="Add one.">`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: Empty merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: use the `align` prop.

[^layout-classes]: test:registry/ouro/components/ouro/empty/empty.test.tsx::Empty > passes attributes and a ref through, and lets layout classes win verify:testExists(registry/ouro/components/ouro/empty/empty.test.tsx::Empty > passes attributes and a ref through, and lets layout classes win)
