Badge
A short label for a status, category or count, next to what it describes.
In Content first
See it live
npm run storybookWhen to use it
In Content first: The topic of an article.
- Use it when: A state people scan for in a list or table, or a small category label.
- Not when: A message people must read (alert or toast), or an action (a button).
Instead:
Variants
What each variant is for in any design system, then what Content first decided and why. Each sample is the live story with that variant set.
neutraltoneUsed in Content firstWhat it is for
A label with no status meaning: a category, a count, a waiting state.
In Content first
Saved: waiting for you; nothing is wrong.
infotoneNot used in Content firstWhat it is for
News: worth knowing, nothing to act on.
In Content first
Topics and reading states need no news tone; status is rare.
successtoneUsed in Content firstWhat it is for
Done, healthy or paid.
In Content first
Finished: you read it to the end.
warningtoneUsed in Content firstWhat it is for
Needs attention soon; nothing has failed yet.
In Content first
Out of date: the facts may have changed since it was written.
dangertoneNot used in Content firstWhat it is for
Failed, blocked or lost; act now.
In Content first
Nothing in an article fails; errors are calm sentences, not labels.
How Content first uses it
Why it works this way
Badge looks the way it does because of 2 answers about this product. Each card is one answer, in three steps: the answer, what it decided for Badge, and what would move if it changed.
accessibility.count1The answer
Status is rare; color and a word are enough.
2So Badge
- ✓uses neutral: Saved: waiting for you; nothing is wrong.
- –does not use info: Topics and reading states need no news tone; status is rare.
- ✓uses success: Finished: you read it to the end.
- ✓uses warning: Out of date: the facts may have changed since it was written.
- –does not use danger: Nothing in an article fails; errors are calm sentences, not labels.
Alert: destructive3If it changed
No other answer follows from it.
voice.count1The answer
Warm by default, calmer for errors.
2So Badge
- –does not use danger: Nothing in an article fails; errors are calm sentences, not labels.
Alert: destructive Toast: danger3If it changed
No other answer follows from it.
Words
- Write to one person: "you", not "users".
- Short sentences with room to breathe.
- Explain why before asking for anything.
- Use: Read, Save for later, You, Next issue. Avoid: Click here, Submit, Users, Content.
The labels components use, from the voice tokens:
content.action.commit: Savecontent.action.cancel: Not nowcontent.action.destroy: Removecontent.action.retry: Try againcontent.action.empty-action: Browse guides
See Voice and tone for the whole voice.
Accessibility and keyboard
Test before you ship:
- The status is a word; color and icon add to it, never replace it. undefined
Use it in code
npx open-ds add badge
The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.
Tokens it reads
Badge reads 17 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Badge's tokens to change Badge alone.
Content first decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.
| Part | Its token and the semantic it aliases | Value |
|---|---|---|
| Badge | ||
| Corner | component.badge.radiusradius.badgevar(--badge-radius) | radius.999:9999px |
| Padding, left and right | component.badge.padding-xspace.gap.tightvar(--badge-padding-x) | space.8:0.5rem |
| Text size | component.badge.font-sizetype.caption.font-sizevar(--badge-font-size) | font.size.14:0.875rem |
| Gap | component.badge.gapspace.gap.tightvar(--badge-gap) | space.8:0.5rem |
| Padding, top and bottom | component.badge.padding-ycomponent-spacing-map.hairlinevar(--badge-padding-y) | space.2:0.125rem |
| Weight | component.badge.font-weighttype.label.font-weightvar(--badge-font-weight) | font.weight.600:600 |
| Font family | component.badge.font-familytype.caption.font-familyvar(--badge-font-family) | font.family.inter:Inter, system-ui, sans-serif |
| Neutral | ||
| Fill Changes with theme | component.badge.neutral.backgroundcolor.surface.sunkenvar(--badge-neutral-background) | Lightstone.light.100:#F6F2EADarkstone.dark.100:#2E2A24 |
| Text Changes with theme | component.badge.neutral.labelcolor.text.secondaryvar(--badge-neutral-label) | Lightstone.light.700:#4A4339Darkstone.dark.500:#CFC6B6 |
| Success | ||
| Fill Changes with theme | component.badge.success.backgroundcolor.status.success.subtlevar(--badge-success-background) | Lightgreen.light.100:#DBF7DFDarkgreen.dark.100:#02351B |
| Text | component.badge.success.labelcolor.text.success-on-lightvar(--badge-success-label) | green.light.800:#023E17 |
| Warning | ||
| Fill Changes with theme | component.badge.warning.backgroundcolor.status.warning.subtlevar(--badge-warning-background) | Lightamber.light.100:#FEE8CFDarkamber.dark.100:#402B00 |
| Text | component.badge.warning.labelcolor.text.warning-on-lightvar(--badge-warning-label) | amber.light.800:#462A02 |
| Danger | ||
| Fill Changes with theme | component.badge.danger.backgroundcolor.status.danger.subtlevar(--badge-danger-background) | Lightred.light.100:#FFDBD8Darkred.dark.100:#4D181A |
| Text | component.badge.danger.labelcolor.text.danger-on-lightvar(--badge-danger-label) | red.light.800:#6D0008 |
| Info | ||
| Fill Changes with theme | component.badge.info.backgroundcolor.status.info.subtlevar(--badge-info-background) | Lightblue.light.100:#D3E4FFDarkblue.dark.100:#172C4F |
| Text | component.badge.info.labelcolor.text.info-on-lightvar(--badge-info-label) | blue.light.800:#001A4E |