What a screen or section shows when there is genuinely nothing in it: what goes here, why, and one way to start.
Light
align="left" · the Kata anatomy
Grading
Nothing graded yet
Add what you’re teaching to start grading.
Add a techniqueSee last month’s listDark
align="left" · the Kata anatomy
Grading
Nothing graded yet
Add what you’re teaching to start grading.
Add a techniqueSee last month’s listSource:
EmptyState.tsx. When a screen should be empty at all, and the loading and error states beside it: states.
When to use it
- After asking whether the screen should be empty. Real data elsewhere that belongs here? Show it. Something you can suggest from a real source? Suggest it.
- Only then: an empty collection. An empty search is different — keep the field and filters and say what matched nothing.
Use align="left" for anything new. The centred shape is frozen for its existing call sites.
Anatomy
align="left" — the Kata anatomy, in flow on the page's own gutter:
| Part | Token |
|---|---|
| Block | spacing.section 24 above and below, no horizontal padding, spacing.s8 between parts |
| Eyebrow | typography.eyebrow, text.secondary |
| Title | typography.title 22/700, text.primary |
| Body | typography.body, text.secondary — what goes here and why |
| Primary | the red pill: brand.red, 48 floor, typography.rowTitle, brand.onRed, spacing.s8 extra above |
| Link | typography.label 13/700 in accent.red, 32 drawn plus hitSlop to 44 |
align="center" — the legacy shape:
Light
align="center" · frozen legacy shape
No events yet
Camps, tests and seminars show up here.
Create an eventDark
align="center" · frozen legacy shape
No events yet
Camps, tests and seminars show up here.
Create an event| Part | Token |
|---|---|
| Block | centred, spacing.s64 vertical, spacing.detailHorizontal 24 horizontal |
| Glyph | 36pt in text.quaternary — off the icon ramp and frozen; do not copy it |
| Title | typography.rowTitle, centred |
| Action | red pill, typography.buttonMedium, spacing.s16 above, hitSlop to 44 |
States
- An empty state is itself a state. Its actions press at
opacity.pressed0.85. - While it shows, demote the screen's other primary: one filled primary per screen.
- Loading is never an empty state. Show nothing under a second, then a spinner or skeleton.
- An error uses the same left anatomy with "Couldn't load …" and a retry.
Content
- Title says what is missing, plainly: "Nothing graded yet".
- Body says what goes here and how it gets there: "Add what you're teaching to start grading."
- No exclamation marks, no "let's", no apology. The ninja may appear in an empty state; a cheerful line about nothing may not.
Accessibility
- The primary and the link are role
button, labelled with their visible text, each 44pt or more. - Left-aligned and in flow, so it is read in the order it is seen, right after the screen title.
Do and don't
Students
No students yet
Invite your first student to start taking attendance.
Invite a studentDo
Left-aligned and in flow: what goes here, why, and one way to start.
Nothing here yet — let’s fix that!
Get startedDon’t
A centred line in a void, cheerful about nothing.
Code
import { EmptyState } from '../../components/ui';
<EmptyState
align="left"
eyebrow="Grading"
title="Nothing graded yet"
subtitle="Add what you're teaching to start grading."
action={{ label: 'Add a technique', onPress: addTechnique, testID: 'grading-empty-add' }}
link={{ label: "See last month's list", onPress: openLastMonth, testID: 'grading-empty-last-month' }}
testID="grading-empty"
/>