Skip to main content

Badge

A short label for a status, category or count, next to what it describes.

In Multi-brand

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Multi-brand: Plan and status 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:

  • Alert: A message, not a label.
  • Button: Something to press.

Variants​

What each variant is for in any design system, then what Multi-brand decided and why. Each sample is the live story with that variant set.

neutraltoneUsed in Multi-brand
Start Storybook to see it live

What it is for

A label with no status meaning: a category, a count, a waiting state.

✓Nothing is wrong and nothing needs doing.
✕The state needs attention.

In Multi-brand

Trial: the plan works and billing has not started.

infotoneUsed in Multi-brand
Start Storybook to see it live

What it is for

News: worth knowing, nothing to act on.

✓Something is happening or coming.
✕Something is wrong or nearly wrong.

In Multi-brand

Renews in 3 days: a payment is coming; nothing has gone wrong.

successtoneUsed in Multi-brand
Start Storybook to see it live

What it is for

Done, healthy or paid.

✓The outcome people wanted.
✕A state that is only waiting.

In Multi-brand

Active: the plan is paid and running.

warningtoneNot used in Multi-brand
Start Storybook to see it live

What it is for

Needs attention soon; nothing has failed yet.

✓A risk people can still act on.
✕Something already failed.

In Multi-brand

No plan or order state sits between running and failed; a coming renewal is news, not a warning.

dangertoneUsed in Multi-brand
Start Storybook to see it live

What it is for

Failed, blocked or lost; act now.

✓A real failure or loss.
✕Anything that is only unusual.

In Multi-brand

Card declined: the payment failed, so the plan will stop.

How Multi-brand uses it​

A status
Use Badge with a word
Not A brand color as status
Brand hues vary, so meaning needs a word.
Shape of a status badge
Use radius.badge (set by the brand)
Not A hard-coded shape
The brand sets the badge shape.

Why it works this way​

Badge looks the way it does because of 3 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.

How many signals carry each meaning?accessibility.count
1The answer
Two: color and word

Brand colors vary, so meaning needs a word.

2So Badge
  • ✓uses neutral: Trial: the plan works and billing has not started.
  • ✓uses info: Renews in 3 days: a payment is coming; nothing has gone wrong.
  • ✓uses success: Active: the plan is paid and running.
  • –does not use warning: No plan or order state sits between running and failed; a coming renewal is news, not a warning.
  • ✓uses danger: Card declined: the payment failed, so the plan will stop.
It also shapes Alert: destructive
3If it changed
5
Badge decisions would reopen

No other answer follows from it.

What is the main content?content.q1
1The answer
Forms and tasks

Product pages, sign-up and account forms.

2So Badge
  • –does not use warning: No plan or order state sits between running and failed; a coming renewal is news, not a warning.
It also shapes Alert: default Input group: inline-start Input group: inline-end Input group: block-start Input group: block-end Item: outline
3If it changed
1
Badge decision would reopen

and 9 answers that follow from it: A moderate amount, Gaps, insets and row heights, Comfortable, and 6 more.

What is a costly mistake?outcomes.q2
1The answer
Looking off-brand

A page that looks like the wrong brand loses trust.

2So Badge
  • ✓uses danger: Card declined: the payment failed, so the plan will stop.
It also shapes Button: secondary Button: danger Alert: destructive
3If it changed
1
Badge decision would reopen

and 1 answer that follow from it: Also for emphasis and size.

Words​

  • Shared structure: object, state, next step.
  • Brand tone lives in headlines and marketing copy, not in errors.
  • Errors and confirmations read the same in every brand.
  • Use: Get started, Plan, Order. Avoid: Brand-specific words in errors, Jargon.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Cancel
  • content.action.destroy: Remove
  • content.action.retry: Try again
  • content.action.empty-action: Get started

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.

Changes with theme

Multi-brand decides what changes when you switch theme. Here a switch changes colors, type and shape, so the marked rows differ between its brands and between light and dark; everything else holds steady.

PartIts token and the semantic it aliasesValue
Badge
Corner
Changes with theme
component.badge.radiusradius.badgevar(--badge-radius)Aster Lightradius.4:0.25remAster Darkradius.4:0.25remBirch Lightradius.999:9999pxBirch Darkradius.999:9999pxCoral Lightradius.999:9999pxCoral Darkradius.999:9999px
Padding, left and rightcomponent.badge.padding-xspace.gap.tightvar(--badge-padding-x)space.8:0.5rem
Text sizecomponent.badge.font-sizetype.caption.font-sizevar(--badge-font-size)font.size.13:0.8125rem
Gapcomponent.badge.gapspace.gap.tightvar(--badge-gap)space.8:0.5rem
Padding, top and bottomcomponent.badge.padding-ycomponent-spacing-map.hairlinevar(--badge-padding-y)space.2:0.125rem
Weightcomponent.badge.font-weighttype.label.font-weightvar(--badge-font-weight)font.weight.600:600
Font family
Changes with theme
component.badge.font-familytype.caption.font-familyvar(--badge-font-family)Aster Lightfont.family.inter:Inter, system-ui, sans-serifAster Darkfont.family.inter:Inter, system-ui, sans-serifBirch Lightfont.family.plus-jakarta-sans:"Plus Jakarta Sans", system-ui, sans-serifBirch Darkfont.family.plus-jakarta-sans:"Plus Jakarta Sans", system-ui, sans-serifCoral Lightfont.family.poppins:Poppins, system-ui, sans-serifCoral Darkfont.family.poppins:Poppins, system-ui, sans-serif
Neutral
Fill
Changes with theme
component.badge.neutral.backgroundcolor.surface.sunkenvar(--badge-neutral-background)Aster Lightslate-deep.light.100:#F1F5F9Aster Darkslate-deep.dark.100:#1E293BBirch Lightslate-deep.light.100:#F1F5F9Birch Darkslate-deep.dark.100:#1E293BCoral Lightslate-deep.light.100:#F1F5F9Coral Darkslate-deep.dark.100:#1E293B
Text
Changes with theme
component.badge.neutral.labelcolor.text.secondaryvar(--badge-neutral-label)Aster Lightslate-deep.light.700:#334155Aster Darkslate-deep.dark.500:#CBD5E1Birch Lightslate-deep.light.700:#334155Birch Darkslate-deep.dark.500:#CBD5E1Coral Lightslate-deep.light.700:#334155Coral Darkslate-deep.dark.500:#CBD5E1
Success
Fill
Changes with theme
component.badge.success.backgroundcolor.status.success.subtlevar(--badge-success-background)Aster Lightgreen.light.100:#DBF7DFAster Darkgreen.dark.100:#012A14Birch Lightgreen.light.100:#DBF7DFBirch Darkgreen.dark.100:#012A14Coral Lightgreen.light.100:#DBF7DFCoral Darkgreen.dark.100:#012A14
Textcomponent.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)Aster Lightamber.light.100:#FEE8CFAster Darkamber.dark.100:#332201Birch Lightamber.light.100:#FEE8CFBirch Darkamber.dark.100:#332201Coral Lightamber.light.100:#FEE8CFCoral Darkamber.dark.100:#332201
Textcomponent.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)Aster Lightred.light.100:#FFDBD8Aster Darkred.dark.100:#410C11Birch Lightred.light.100:#FFDBD8Birch Darkred.dark.100:#410C11Coral Lightred.light.100:#FFDBD8Coral Darkred.dark.100:#410C11
Textcomponent.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)Aster Lightblue.light.100:#D3E4FFAster Darkblue.dark.100:#0D2244Birch Lightblue.light.100:#D3E4FFBirch Darkblue.dark.100:#0D2244Coral Lightblue.light.100:#D3E4FFCoral Darkblue.dark.100:#0D2244
Textcomponent.badge.info.labelcolor.text.info-on-lightvar(--badge-info-label)blue.light.800:#001A4E