Zetta v1.6

Components · Data display & feedback

Empty state

The component behind a blank screen — a centred icon-tile, a heading, a one-line description, and the action that fills the void. Now a first-class spec in v1.2 (the Patterns section shows the composition; this is the tokenised primitive).

Preview

No projects yet

Create your first project to start deploying — import from Git or begin from a template.

Build with the skill

No package to install — hand this to your AI to generate or migrate the component in your stack.

Prompt for your AI
Apply the Zetta "Empty state" component to this project using the zetta-design-md skill.

WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `empty-state` spec (variants: default, compact) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `empty-state` spec in this project's stack.

AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.

ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility.

Anatomy & rules

         ╭──────╮
         │  ★   │  ← icon-tile-lg or illustration
         ╰──────╯

    No projects yet

    Create your first project to get
    started with your team.          ← description (max 360px wide)

    [Create project]  [Learn more]   ← primary + secondary action
State Visual
Default Illustration + heading + body + optional action
With action hover Action button applies its own hover state

When to use

  • Tables with zero rows.
  • Lists, grids, or panels with no content.
  • Search results with no matches.
  • Restricted or inaccessible content.

When not to use

  • Loading states — use Skeleton instead.
  • As a placeholder before the user interacts — only show after a data fetch completes.

Do

  • Always include a heading. Description and action are optional but recommended.
  • Make the primary action directly resolve the empty state ("Create project", "Add member").
  • Match the icon or illustration to the type of missing content.

Don't

  • Don't use generic headings like "Nothing here" — be specific about what is missing.
  • Don't show more than two actions.
  • Heading: "No [items] yet" or "No results for [X]". 3–6 words.
  • Description: 1–2 sentences max. Explain why and what to do. "Create your first project to get started."
  • Primary action: verb phrase matching the creation action. "Create project", not "Get started".

Keyboard

Empty State has no keyboard behavior of its own. When it includes an action button, keyboard interaction follows the standard Button spec.

Accessibility

  • Heading renders as appropriate <h> level matching the page hierarchy — not always <h2>.
  • If the empty state appears inside a table: render it as a <tr><td colspan="N"> row — do not replace the table with a div.
  • Primary action must be a <button> or <a> — not a <div>.

Spec

Values and token references resolved straight from the Zetta spec.

empty-state
display
flex
flexDirection
column
alignItems
center
justifyContent
center
textAlign
center
gap
{spacing.md}
paddingX
{spacing.xl}
paddingY
{spacing.2xl}
empty-state-illustration
width
80px
height
80px
marginBottom
{spacing.sm}
empty-state-icon-tile
marginBottom
{spacing.sm}
empty-state-heading
fontFamily
Inter
fontSize
18px
fontWeight
600
lineHeight
1.35
textColor
{colors.ink}
empty-state-description
fontFamily
Geist
fontSize
14px
fontWeight
400
lineHeight
1.60
textColor
{colors.muted}
maxWidth
360px
empty-state-actions
display
flex
alignItems
center
gap
{spacing.sm}
marginTop
{spacing.xs}
empty-state-compact
paddingX
{spacing.md}
paddingY
{spacing.lg}
empty-state-compact-heading
fontFamily
Geist
fontSize
14px
fontWeight
500
textColor
{colors.muted}
empty-state-compact-description
fontSize
12px
textColor
{colors.muted}