Photon Design System

Status View

One view for a region with nothing to show or nothing that worked — icon over title over description, with an optional action row. The block shrink-wraps and centers itself; text stays left-aligned so the icon / title / description share one edge. The host decides the footprint: drop it in a card body, or wrap it in min-h-screen flex centering for a full page. Use size="sm" inside cards and panels; the default base for whole pages.

Empty and error states are the same component — they differ only in what you pass (icon, role, actions), not in how they look.

Import

import { StatusView } from "@photon-ai/pho-ui/components/status-view";

Sizes

Two sizes, retuning every slot. Title and description share Dialog’s font-display ladder — base matches Dialog (gap-1); sm steps one rung down (no gap):

  • sm — cards and panels (py-8, icon size-6 + mb-1.5, copy gap-0, title / description text-base)
  • base (default) — full pages (py-12, icon size-10 + mb-4, copy gap-1, title text-display-sm, description text-display-xs)
No API keys yet
Create one to call Photon from CI or a server.
sm
No API keys yet
Create one to call Photon from CI or a server.
base
<StatusView size="sm" icon={<IconKey />} title="No API keys yet" … />
<StatusView size="base" icon={<IconKey />} title="No API keys yet" … />

Empty

A quiet placeholder for a region with nothing to show yet. Usually no action row — the create affordance normally lives elsewhere on the page.

No API keys yet
Create one to call Photon from CI or a server.
<StatusView
  size="sm"
  icon={<IconKey />}
  title="No API keys yet"
  description="Create one to call Photon from CI or a server."
/>

Error

For failures, pass a warning icon, role="alert" so the state announces, and actions offering a way out — retry, reload, or a route back.

This page couldn't load
Reload to try again, or go back.
<StatusView
  role="alert"
  icon={<IconAlertTriangle />}
  title="This page couldn't load"
  description="Reload to try again, or go back."
  actions={
    <>
      <Button size="sm" onClick={() => window.location.reload()}>
        Reload
      </Button>
      <Button
        size="sm"
        variant="outlined"
        onClick={() => window.history.back()}
      >
        Back
      </Button>
    </>
  }
/>

Not found

The same view covers 404s — one action routing back is enough.

Page not found
This address doesn't exist, or the page has moved.
<StatusView
  role="alert"
  icon={<IconAlertTriangle />}
  title="Page not found"
  description="This address doesn't exist, or the page has moved."
  actions={
    <ButtonLink href="/" size="sm">
      Go home
    </ButtonLink>
  }
/>

Guidelines

  • Keep the title to one short line naming the state; put the “what now” in the description.
  • Empty states don’t need an action row — reserve actions for errors, where the user is stuck without one.
  • Pass role="alert" only for failures; an empty region is a normal state and shouldn’t interrupt a screen reader.
  • Title and description sit in a Dialog-style stack (gap-0 / gap-1); actions sit mt-5 below (Dialog body spacing).
  • The view only brings its own breathing room (py-8 / py-12) and hugs its content (w-fit), capped at max-w-lg so long prose still wraps. Center it with the host (min-h-screen + flex centering) for full-page use.