Empty, loading and error
A container that loads data has three states before it has any: nothing yet, still coming, failed. A screen that shows only the fourth — the data — is a screen that looks broken three times a day. The State block composes Empty, Skeleton and Alert as one component so the three cannot drift apart, in two contexts: a table and a card.
Beta · Pattern · states.css · empty.css · skeleton.css · alert.css and 3 more · drawn in the library as a campaigns table in its three states
Empty / loading / error states · Empty · Skeleton · Alert / Banner · Spinner · Progress · Button
The workshop's own story, rendered here: the three states down, the two contexts across. The skeleton rows match the rows they stand in for; the error carries its Retry.
What it is for
Section titled “What it is for”Use when any table, list, card or panel that loads data — every data container carries all three. Do not use when the whole page failed (a page-level Alert or an error page); a form’s field error (Field); a control’s own busy state (Spinner in a Button). The block is for the container; a control’s own wait is the Spinner inside it, and a task’s known progress is Progress.
The components it is made of
Section titled “The components it is made of”One row per part: its job here, and when the part itself is the one to use. Its own page holds the rest — the markup, the modifiers, the measured rows.
| Component | Its job in the arrangement | Use it when |
|---|---|---|
| Empty / loading / error states | the three states of one container, composed as one block | any table, list, card or panel that loads data — every data container carries all three |
| Empty | nothing to show: what belongs here and the way to put it there | 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 |
| Skeleton | loading, when the layout is known: the rows in grey, then the content fills them | a region whose layout is known is loading — a table, a card grid, a profile header — and the wait is longer than a blink |
| Alert / Banner | failed: the danger tone, and a way to retry when a retry would work | a message that must stay until the user acts or the state changes — a failed sync, a plan limit, a saved confirmation that should remain, a data warning above a table |
| Spinner | a wait with no known layout — a button submitting, a panel refreshing — never a container | a wait under a few seconds with no known layout — a button submitting, a panel refreshing |
| Progress | a wait with a known share done | a task has a known share done — an upload, an import, a generation with steps, a questionnaire’s position (step n of m) |
| Button | the Retry beside the error, the verb in an empty state | the one action a view exists for — submit, save, create |
The rules that hold between them
Section titled “The rules that hold between them”- Every data container has all three. Any table, list, card or panel that loads data — every data container carries all three.
- What each context shows. State block — what a data container shows before its data, while it comes, and when it fails: Empty, Skeleton and Alert composed as one component, the three states the product kit lists for every data container. Context table (1200, the Data table’s width): empty is Empty’s block with its dashed border, loading is five Skeleton rows (a small circle, a medium and a small line, a long line filling the rest — a row’s shape), error is Alert in the danger outline with a Retry (Button - secondary small) beside it. Context card (368, Card’s): Empty’s inline line, three Skeleton lines, the soft danger Alert. Never a Spinner for a container — a spinner says wait, a skeleton says what is coming; Spinner is for a control (a button, a field).
- Never a Spinner for a container, and never an error without its retry. Never: a spinner where a skeleton belongs · an error with no way to retry when a retry would work · ‘Error’ as a title · a skeleton that does not match the rows it stands in for · a fill changed on the instance.
- What the empty state says. 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.
- What it never is. Never: 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.
- Where loading goes. Skeleton — a region whose layout is known is loading — a table, a card grid, a profile header — and the wait is longer than a blink. Spinner — a wait under a few seconds with no known layout — a button submitting, a panel refreshing. Progress — a task has a known share done — an upload, an import, a generation with steps, a questionnaire’s position (step n of m).
- A skeleton is the size of what it stands for. Never: a skeleton that is not the size of the content (the jump is worse than the wait) · a skeleton for a button · more than one pulse rhythm on a screen · a skeleton with a border.
In the library
Section titled “In the library”The Figma page States — empty, loading, error draws the block’s example — the State block set.
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.