A status pill: a fill and a short label. It states a fact and never takes a tap.
Light
neutral
Drafterror
Overduewarning
Expires sooninfo
Newsuccess
Paidgold
PromotedDark
neutral
Drafterror
Overduewarning
Expires sooninfo
Newsuccess
Paidgold
PromotedSource:
Badge.tsx. When status belongs in a badge rather than a banner or a push: notifications.
When to use it
- To mark the state of one thing in a list: "Overdue", "Paid", "Draft".
- In a Row's trailing slot, or under a detail screen's title.
Not as a filter or a choice — that is a chip, which has an edge and a press. Not
for a value with a label ("12 classes") — that is StatPill. Not for a belt's verification
state — that is BeltStateBadge.
Anatomy
| Part | Token |
|---|---|
| Height floor | 24 (spacing.s24); grows with the label |
| Padding | spacing.s4 × spacing.s8 |
| Shape | radius.pill |
| Label | typography.label 13/700, sentence case |
Each tone pairs a fill with its own text colour:
| Tone | Fill | Text |
|---|---|---|
neutral (default) |
surface.tag |
text.secondary |
error |
feedback.errorFill |
feedback.errorText |
warning |
feedback.warningFill |
feedback.warningText |
info |
feedback.infoFill |
feedback.infoText |
success |
feedback.successFill |
feedback.successText |
gold |
gold.fill |
gold.text |
Light
In a row’s trailing slot
Dark
In a row’s trailing slot
States
A badge has one state: shown. It has no pressed, focus, disabled or loading state because it is not a control. Change its tone or label when the thing it describes changes.
Content
- One or two words, sentence case: "Expires soon", not "EXPIRES SOON".
- Say the state, not the instruction: "Overdue", not "Pay now".
- Never colour alone. The word carries the meaning; the tone reinforces it.
Accessibility
- No role: it is read as part of the row or heading it sits in. Make sure that container's label includes it ("Jordan Lee. Membership. Overdue").
- The fills are nearly the page's colour, so the text colour carries the severity; every text token clears 4.5:1 on its own fill in both themes.
- It never has a
border.controledge, because an edge says "tap me".
Do and don't
Do
Sentence case. The text colour carries the severity.
Don’t
Capitals. The eyebrow is the one uppercase register, and badges are not it.
Code
import { Badge, Row } from '../../components/ui';
<Row title="Jordan Lee" subtitle="Membership" trailing={<Badge label="Overdue" tone="error" />} onPress={open} />