Skip to content

Documentation

neelam-ui

Search documentation

Getting Started
Forms
Overlays
Navigation
Data Display
Layout
AI & Chat
Blocks
GitHub repository

Empty State

The “nothing here yet” panel — before the first record exists, after a filter matches nothing, or when a feature has not been used.

No projects yet

Create your first project to start deploying. It takes about a minute.

Usage#

import { Button, EmptyState } from "neelam-ui";
 
<EmptyState
  icon={<FolderPlus className="h-5 w-5" />}
  title="No projects yet"
  description="Create your first project to start deploying."
  action={<Button>New project</Button>}
/>

Write the title as a short statement of what is missing — "No projects yet", not "Empty". The description is what turns a dead end into an instruction, and action is the way out.

Choosing the heading level#

title renders as a <p> by default, not a heading. An empty state can appear inside a card, a table body, a tab panel, or as a whole page, and only you know which level the surrounding outline calls for — guessing produces skipped heading levels (WCAG 1.3.1).

Pass titleAs where the empty state owns a section:

<EmptyState titleAs="h2" title="No results" />

Why titleAs names the element

The alternative — passing a heading element as title — would nest an <h2> inside the <p> that styles it, which is invalid HTML. Naming the element lets the level be chosen without that.

This is the same problem Card has, resolved differently: a card's nesting is predictable enough to fix CardTitle at <h3>, and an empty state's is not.

Announcing a state that replaces content#

live renders the region as role="status" with aria-live="polite", so an empty state that appears in place of content is announced — a filter matching nothing, or a finished load returning zero rows:

<EmptyState live title="No results" description="Try a different search." />

Leave it off — the default — when the empty state is there on first paint. A live region announces changes, so one present from the start announces nothing anyway, and marking it live only risks a stray announcement later.

Keyboard#

Keyboard shortcuts
KeyBehaviour
TabReaches whatever you pass as action. The panel itself is not focusable.

Move focus when the state swaps in

If an empty state replaces a list the user was working in, their focus may have just been destroyed with it. Moving focus to the empty state's action — or its heading, with tabIndex={-1} — keeps the keyboard user oriented.

Accessibility#

  • icon is aria-hidden throughout. It always duplicates the title beside it, the same treatment Badge and Button give their icon slots.
  • The default <p> title avoids inventing a heading level, which is the more common mistake than omitting one.
  • live is opt-in rather than always on, so an empty state on first paint does not register a live region that can only misfire later.
  • The dashed border is decoration; the title and description carry the meaning, so the state reads correctly with styles off.

API reference#

Props for EmptyState
PropTypeDefault
titlerequired

What's missing, as a short statement — "No projects yet", not "Empty".

ReactNode
action

The way out — typically a `Button`. Rendered under the description.

ReactNode
description

Why it's empty and what will fill it. Optional, but it's what turns a dead end into an instruction.

ReactNode
icon

A decorative illustration or icon above the title. Hidden from assistive tech.

ReactNode
live

Renders the region as `role="status"` with `aria-live="polite"`, so an empty state that *replaces* content in place (a filter matching nothing, a finished load returning zero rows) is announced. Leave off — the default — when the empty state is present on first paint, where a live region would announce nothing anyway.

booleanfalse
titleAs

Which element renders the `title`. Defaults to `"p"` — pass the heading level the surrounding outline calls for (`"h2"`, `"h3"`, …) where the empty state owns a section of the page.

enump

Also accepts every native <div> attribute except title, which is taken over above. Anything passed as children renders after the action.