Skip to content
cennge-ui
GitHubv0.3.1, changelog

EmptyState

What a list, a search or a page shows when there is nothing in it, and the way out.

No repository matches “kotlin”

Search looks at repository names in Cennge.

  1. Press Clear search: the action is an ordinary Button passed in actions, and the list comes back.
  2. Type a name that matches nothing, and the empty state takes the list's place again.
  3. The icon is decorative; screen readers get the title, the description and the buttons.
Live: clear the search, type in it.

Field marks

Import
import { EmptyState } from "cennge-ui";
Size
0.7 KB gzip for this import, its dependencies aside
Pattern
Two <p> and your buttons, centred; the icon box is aria-hidden
SSR
Rendered on the server in the Next.js check; hydrates without a warning
Sizes
md for a page or a panel, sm for a table body or a short list; icon box 48 or 40 px
Tests
Unit tests

When to use#

Show an EmptyState wherever a list can come back with nothing: the first visit before anything exists, a search with no match, a filter that leaves no rows. Say why it is empty and put the way out right under it, as a button: create the first item, clear the search.

Similar#

  • Alert reports something that happened; an empty state describes a place with nothing in it.
  • Skeleton stands in while content loads. Show the empty state only once loading is over.
  • Table takes an empty state as emptyContent and shows it in place of the rows.

First run#

The default size, without an edge, for a page or a panel that has never had anything in it. The icon sits in a raised tile; pass any SVG and it is sized for you.

No open issues

Bugs and ideas for ai-niche-scout will collect here.

first-run.tsx
import { Button, EmptyState } from "cennge-ui";

function IssueIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
      <circle cx="12" cy="12" r="9" />
      <circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none" />
    </svg>
  );
}

export default function NoIssues() {
  return (
    <EmptyState
      icon={<IssueIcon />}
      title="No open issues"
      description="Bugs and ideas for ai-niche-scout will collect here."
      actions={
        <>
          <Button color="primary">New issue</Button>
          <Button variant="flat">View closed</Button>
        </>
      }
    />
  );
}

No results#

variant="bordered" draws a dashed edge around it, and size="sm" tightens the spacing and the type. Repeat the query or the filters in the description, so the reader sees what to change.

No workflow runs match these filters

Branch: feat/charts · Status: failed · Last 7 days

no-results.tsx
import { Button, EmptyState } from "cennge-ui";

export default function NoResults() {
  return (
    <EmptyState
      variant="bordered"
      size="sm"
      title="No workflow runs match these filters"
      description="Branch: feat/charts · Status: failed · Last 7 days"
      actions={
        <Button size="sm" variant="flat">
          Clear filters
        </Button>
      }
      className="max-w-md"
    />
  );
}

Inside a table#

TableBody shows its emptyContent across all columns when it has no rows, so the header stays and the table keeps its shape.

TagPublished

No releases yet

Tag a commit on main to publish the first one.

in-table.tsx
import { Button, EmptyState, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "cennge-ui";

interface Release {
  tag: string;
  date: string;
}

const releases: Release[] = [];

export default function ReleasesTable() {
  return (
    <Table aria-label="Releases of payload-cache" className="w-full">
      <TableHeader>
        <TableColumn>Tag</TableColumn>
        <TableColumn>Published</TableColumn>
      </TableHeader>
      <TableBody
        emptyContent={
          <EmptyState
            size="sm"
            title="No releases yet"
            description="Tag a commit on main to publish the first one."
            actions={
              <Button size="sm" variant="flat">
                Draft a release
              </Button>
            }
          />
        }
      >
        {releases.map((release) => (
          <TableRow key={release.tag}>
            <TableCell>{release.tag}</TableCell>
            <TableCell>{release.date}</TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  );
}

Props#

PropTypeDefault
icon
React.ReactNode
–
titlerequired
React.ReactNode
–
description
React.ReactNode
–
actions
React.ReactNodeButtons that get the user out of the empty state, e.g. "Create issue".
–
variant
"bordered""plain"
"plain"
size
"sm""md"
"md"

Also takes every attribute of <div>, except title, which mean something else here.