Empty
Empty — what a screen says when there is nothing to show, and what to do about it.
Beta · Feedback and status · packages/css/src/components/empty.css
.pui-empty (block; --border; __media __text __title __description __actions) · --inline.
Sizes across, states down.
What it is for
Section titled “What it is for”- Title; Description + Has description; Has media + Icon (swap); Has actions + the exposed Button group (a secondary and the one verb that fills the emptiness — New campaign, Import, Upload); Has border
- Style: block (a page, a card, a table body, a drop zone) · inline (a menu, a list, a cell — Title only)
- No states; with Skeleton (loading) and Alert (error) it is the empty / loading / error trio
Use when a container that will hold things holds none yet, or a query returns nothing — say what belongs here and offer the way to put it there.
Do not use when the data failed to load (Alert, danger); it is still loading (Skeleton); the user has no access (Alert or a page); as decoration on a page that is simply short.
Relates to Skeleton, Alert, Button group, Data table, Combobox menu, Card, Icon.
Anti-patterns a sad-face illustration · a title that says ‘Empty’ · a block empty inside a 36px menu (that is inline) · an empty state with no verb when the user can add the thing · a fill changed on the instance.
Keywords: empty, empty state, no data, no results, zero state, placeholder
Figma — page Empty: Empty (2 variants)
shadcn: empty
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens empty.css.
<div class="pui-empty pui-empty--border"> <span class="pui-empty__media"><span class="pui-icon pui-icon--24">…folder…</span></span> <div class="pui-empty__text"><p class="pui-empty__title">No campaigns yet</p> <p class="pui-empty__description">Create one, or import from a CSV.</p></div> <div class="pui-button-group pui-empty__actions">…</div></div><div class="pui-empty pui-empty--inline">No results.</div>The modifiers
Section titled “The modifiers”| What it is | Note | |
|---|---|---|
| Style | (none) block · --inline | — |
| Extra | --border — the dashed border | — |
Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”| ink on ground | reads | floor | the matrix calls it | |
|---|---|---|---|---|
#544d4d on #ffffff |
8.24 | 4.5 | text.muted on surface.page (promised) | ok |
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
#ffffff on #0b0202 |
20.51 | 4.5 | Primary button label (promised) | ok |
3 distinct pair(s) rendered, 0 that axe calls a violation.
The focus ring
Section titled “The focus ring”2 of 2 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.
Keyboard
Section titled “Keyboard”Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.