Components · Feedback
The deliberately calm face of a region with nothing in it — <EmptyState> centers a faint icon, a title, a muted supporting line and one clear action. It is not an error look: it says “there’s nothing here yet, and here’s how to fill it.” Two flavours cover almost everything — no-data (a region that hasn’t been populated) and no-results-for-search (a query that matched nobody). The icon is decorative; the title carries the meaning.
No notifications yet
When a team lead posts an update or invites you to a rescue event, it’ll show up here.
No volunteers match “husky”
Try a broader search, or clear the filters to see everyone on the roster.
Same layout, different read. No-data offers the generative move (a solid primary CTA to go make something exist); no-results offers the corrective one (a low-key ghost “clear filters” to widen the net). The active query rides in a dismissible chip in the panel head so the empty title can name it.
You’re all caught up
No pending intake reviews — nice work.
Icon, description and action are all optional — drop to a bare title when a full illustration would be noise (a cleared queue). The states above are pinned with an .is-hover / .is-focus class that shares the real :hover / :focus-visible rule — hover brightens the strong accent (keeps the label AA), focus paints the 2px --accent-ring.
32px box at --faint. Decorative — aria-hidden; the title carries meaning. Omit for the minimal state.14px, medium weight, --text. Name the emptiness (and, for a search, echo the query).<Button>, spaced 16px below the copy. primary for generative (no-data), ghost for corrective (no-results).ErrorState — same centered layout, a fixed --bad glyph and a retry.Source · EmptyState.tsx (icon · title · description · action, py-12 text-center) with Button.tsx variants primary / ghost · sibling ErrorState.tsx · design-system/feedback.