Badge
A short label for a status, category or count, next to what it describes.
In Brand expressive
See it live
npm run storybookWhen to use it
In Brand expressive: New and limited labels.
- 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 Brand expressive decided and why. Each sample is the live story with that variant set.
neutraltoneUsed in Brand expressiveWhat it is for
A label with no status meaning: a category, a count, a waiting state.
In Brand expressive
New: a label, not a state to fix.
infotoneNot used in Brand expressiveWhat it is for
News: worth knowing, nothing to act on.
In Brand expressive
Campaign labels are a state or a nudge; there are no plain news labels.
successtoneUsed in Brand expressiveWhat it is for
Done, healthy or paid.
In Brand expressive
On the list: you joined and your place is saved.
warningtoneUsed in Brand expressiveWhat it is for
Needs attention soon; nothing has failed yet.
In Brand expressive
Almost gone: few left, act soon.
dangertoneNot used in Brand expressiveWhat it is for
Failed, blocked or lost; act now.
In Brand expressive
Nothing on a launch page is labeled as failed; errors are plain sentences.
How Brand expressive uses it
Why it works this way
Badge looks the way it does because of 4 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
Color and word.
2So Badge
- ✓uses neutral: New: a label, not a state to fix.
- ✓uses success: On the list: you joined and your place is saved.
- ✓uses warning: Almost gone: few left, act soon.
Alert: destructive3If it changed
No other answer follows from it.
content.q11The answer
Images, campaigns and short punchy copy.
2So Badge
- –does not use info: Campaign labels are a state or a nudge; there are no plain news labels.
Empty: default Input group: block-start Input group: block-end3If it changed
and 10 answers that follow from it: One idea at a time, Browse and explore, Regular, and 7 more.
outcomes.q11The answer
Engagement and sign-ups.
2So Badge
- ✓uses warning: Almost gone: few left, act soon.
Button: primary Button: large Toast: success Toggle: lg3If it changed
and 6 answers that follow from it: A few minutes, Brand moments, Hero and launch moments, and 3 more.
voice.count1The answer
Playful in headlines, plain in errors.
2So Badge
- –does not use danger: Nothing on a launch page is labeled as failed; errors are plain sentences.
Toast: neutral Toast: danger Alert: default Alert: destructive3If it changed
No other answer follows from it.
Words
- Headlines are short and bold. Three to six words.
- Verbs that move: Join, Try, Go.
- Playful in headlines, plain in errors.
- Use: Join, Drop, Go, Love. Avoid: Synergy, Leverage, Kindly.
The labels components use, from the voice tokens:
content.action.commit: Gocontent.action.cancel: Not nowcontent.action.destroy: Removecontent.action.retry: Try againcontent.action.empty-action: Explore the drop
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.
Brand expressive 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.700:700 |
| Font family | component.badge.font-familytype.caption.font-familyvar(--badge-font-family) | font.family.dm-sans:"DM Sans", system-ui, sans-serif |
| Neutral | ||
| Fill Changes with theme | component.badge.neutral.backgroundcolor.surface.sunkenvar(--badge-neutral-background) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Text Changes with theme | component.badge.neutral.labelcolor.text.secondaryvar(--badge-neutral-label) | Lighttaupe.light.700:#4D3A33Darktaupe.dark.500:#E2C4B3 |
| Success | ||
| Fill Changes with theme | component.badge.success.backgroundcolor.status.success.subtlevar(--badge-success-background) | Lightgreen.light.100:#DBF7DFDarkgreen.dark.100:#013118 |
| 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:#3B2701 |
| 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:#481316 |
| 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:#13284B |
| Text | component.badge.info.labelcolor.text.info-on-lightvar(--badge-info-label) | blue.light.800:#001A4E |