Skip to content

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.

When this pattern applies

Primary triggers

All triggers

Specification body

Pattern — Empty state

Status: v0.1.0 — Draft. First entry of the new specs/patterns/ group (resolver in tools/design-gen/internal/spec/parse.go updated to route patterns/*.kmd to 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

ElementRequiredNotes
Illustration / iconRecommendedDecorative; supports the message but never carries it alone (a11y: alt="" or role="presentation")
HeadingYesOne short sentence; sentence case
BodyYes1–2 sentences explaining what was expected here + how to populate it
Primary actionRecommendedSingle CTA labeled with a verb (Create your first note, Invite your team)
Secondary linkOptionalInline 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 empty not No 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).

References