Empty state pattern
patterns specs/patterns/empty-state.kmd
Purpose-built UI for "no data yet" surfaces — illustration + heading + body + primary action. Treats absence-of-data as a first-class UX moment, not a fallback. Modeled after Polaris (Shopify) EmptyState and Evergreen (Segment) empty-state catalogue.
Quando este padrão se aplica
Triggers primários
- Render an empty inbox / search-no-results / fresh dashboard
Todos os triggers
- Design a surface that can have no rows / no results / no items
- Replace a blank fallback or generic spinner with a guided state
Corpo da especificação
Pattern — Empty state
Status: v0.1.0 — Draft. First entry of the new
specs/patterns/group (resolver intools/design-gen/internal/spec/parse.goupdated to routepatterns/*.kmdto kind=pattern). Live URL once rendered:kds.koder.dev/<locale>/patterns/patterns-empty-state.html.
R1 — When to use
Use an empty state when:
- A surface that normally lists/displays records has zero records.
- A search/filter returns no matches.
- A first-run product surface has no user data yet.
Do NOT use an empty state when:
- The surface is loading (use a skeleton — see
specs/components/skeleton.kmd). - The surface failed to load (use an error pattern — separate spec).
- Permissions block the data (use access-restriction —
specs/patterns/feature-paywall.kmd).
R2 — Anatomy
| Element | Required | Notes |
|---|---|---|
| Illustration / icon | Recommended | Decorative; supports the message but never carries it alone (a11y: alt="" or role="presentation") |
| Heading | Yes | One short sentence; sentence case |
| Body | Yes | 1–2 sentences explaining what was expected here + how to populate it |
| Primary action | Recommended | Single CTA labeled with a verb (Create your first note, Invite your team) |
| Secondary link | Optional | Inline help link (Learn how this works) |
R3 — Tone
- Encouraging, never apologetic ("Let's get started" not "Sorry, nothing here yet").
- Second-person, active voice ("Create your first…", not "Records will appear here").
- Specific to the surface (
Your inbox is emptynotNo data found). - Per
specs/content/voice-and-tone.kmd— empty-state copy uses the first-run tone column of the tone matrix.
R4 — Illustration source
- When the Koder brand library has a matching illustration: use it.
- Fallback: a single Verge token-colored icon at 64×64.
- Never: stock photos, third-party clipart, or AI-generated images inserted without review.
R5 — i18n
All strings translatable per specs/i18n/contract.kmd. Heading + body +
CTA each have separate translation keys (no concatenation in code).
Illustrations are locale-neutral (no embedded text).
R6 — Accessibility
- The illustration is decorative (alt="").
- Heading uses
<h2>(or appropriate level for surface hierarchy). - Primary action is a real
<button>or<a>with keyboard focus + visible focus ring (Verge--kds-color-focus). - The empty-state container surfaces a single live-region announce on first appearance: "{heading}. {body}." Screen-reader users learn the state without scanning the whole tree.
Não-escopo
- Brand-specific illustrations (handed off to
meta/brand/koder-design). - Animation on appear (out of v0).
- A/B-tested CTA variants (product-level concern).
Referências
specs/components/data-table.kmdspecs/patterns/callout-card.kmdspecs/content/voice-and-tone.kmd