Display

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.

No recipes yet

Start by creating your first recipe for this pantry.

In Spoonjoy

Spoonjoy, a recipe app, is built with Ouro HX (how).

In its source: app/routes/my-recipes.tsx · app/components/recipe/SpoonsStrip.tsx · app/components/cookbook/KitchenHome.tsx

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/empty#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/empty

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/empty#v1.2.13 ourostack/ouro-ui/empty-tests#v1.2.13
import { Empty } from "@/components/ouro/empty/empty";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<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.

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

Claim sources