Monet
@etched/monet 0.0.1

Empty

Ported

Placeholder for a list, table or page with nothing to show. The title is a heading. Native <div> attributes and ref pass through.

Kumo source

No runs yet

Runs you start appear here.

import { PlusIcon, TrayIcon } from "@phosphor-icons/react";
import { Button } from "@etched/monet/button";
import { Empty } from "@etched/monet/empty";

export function Preview() {
  return (
    <Empty
      size="sm"
      icon={<TrayIcon />}
      title="No runs yet"
      description="Runs you start appear here."
      contents={
        <Button variant="primary" icon={<PlusIcon />}>
          New run
        </Button>
      }
    />
  );
}

Installation

import { Empty } from "@etched/monet/empty";

Examples

With actions

No runs yet

Runs you start on a bench appear here, newest first.

import { PlusIcon, TrayIcon } from "@phosphor-icons/react";
import { Button } from "@etched/monet/button";
import { Empty } from "@etched/monet/empty";

export function WithActions() {
  return (
    <Empty
      icon={<TrayIcon />}
      title="No runs yet"
      description="Runs you start on a bench appear here, newest first."
      contents={
        <div className="row">
          <Button>Import runs</Button>
          <Button variant="primary" icon={<PlusIcon />}>
            New run
          </Button>
        </div>
      }
    />
  );
}

Sizes

No data (sm)

There is no data for this bench yet.

No data (base)

There is no data for this bench yet.

No data (lg)

There is no data for this bench yet.

import { DatabaseIcon } from "@phosphor-icons/react";
import { Empty, type EmptySize } from "@etched/monet/empty";

const sizes: EmptySize[] = ["sm", "base", "lg"];

export function Sizes() {
  return (
    <div className="grid">
      {sizes.map((s) => (
        <Empty key={s} size={s} icon={<DatabaseIcon />} title={`No data (${s})`} description="There is no data for this bench yet." />
      ))}
    </div>
  );
}

Plain, inside a card or a table

appearance="plain" drops the edge and the fill: the card or the table has its own. Under a card's h2 title, titleAs="h3" keeps the headings in order.

Referrals

No referrals yet

Referrals for this role appear here.

Open roles

RoleCandidates

No open roles match these filters.

import { UsersThreeIcon } from "@phosphor-icons/react";
import { LayerCard } from "@etched/monet/layer-card";
import { Table } from "@etched/monet/table";
import { Empty } from "@etched/monet/empty";

export function PlainInsideACardOrATable() {
  return (
    <div className="rows" style={{ maxInlineSize: "36rem" }}>
      <LayerCard title="Referrals">
        <Empty
          appearance="plain"
          size="sm"
          titleAs="h3"
          icon={<UsersThreeIcon />}
          title="No referrals yet"
          description="Referrals for this role appear here."
        />
      </LayerCard>
      <LayerCard size="none" title="Open roles">
        <Table aria-label="Open roles" density="dense">
          <thead>
            <tr>
              <th>Role</th>
              <th style={{ inlineSize: "6rem" }}>Candidates</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td colSpan={2}>
                <Empty appearance="plain" size="sm" titleAs="h3" title="No open roles match these filters." />
              </td>
            </tr>
          </tbody>
        </Table>
      </LayerCard>
    </div>
  );
}

Error and text only

Without a description, the title shows as muted text.

No connection

Orbit cannot reach the server. Check your connection and try again.

No references or referrals yet.

import { CloudSlashIcon } from "@phosphor-icons/react";
import { Button } from "@etched/monet/button";
import { Empty } from "@etched/monet/empty";

export function ErrorAndTextOnly() {
  return (
    <div className="grid">
      <Empty
        size="sm"
        icon={<CloudSlashIcon />}
        title="No connection"
        description="Orbit cannot reach the server. Check your connection and try again."
        contents={<Button variant="primary">Retry</Button>}
      />
      <Empty size="sm" title="No references or referrals yet." />
    </div>
  );
}

Accessibility

  • The title is a heading, h2 by default. The description and contents follow it.
  • It is not a live region: when a filter empties a list, screen readers do not hear it.
  • Set titleAs to fit the outline, such as h3 in a card whose title is an h2.

API reference

PropTypeDefaultDescription
size"sm" | "base" | "lg""base"
appearance"card" | "plain""card"
iconReactNode–Decorative icon above the title, for example <TrayIcon />. Sized and colored by the size.
title *ReactNode–What is empty: "No runs yet". A large heading with a description, muted text without one.
titleAs"h2" | "h3" | "h4" | "h5" | "h6""h2"The title's element, for its place in the outline: h3 inside a card whose title is an h2.
descriptionReactNode–What to do next: "Runs you start appear here."
contentsReactNode–Actions below the text, such as a row of buttons.