Skip to main content

Badge

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

In Dense data

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Dense data: Alert status in rows.

  • 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 Dense data decided and why. Each sample is the live story with that variant set.

neutraltoneUsed in Dense data
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 Dense data

New and False positive: not triaged yet, or a finished outcome that is not a failure.

infotoneUsed in Dense data
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 Dense data

Investigating: an analyst is on it; news, nothing to act on.

successtoneUsed in Dense data
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 Dense data

Resolved: contained and closed.

warningtoneUsed in Dense data
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 Dense data

Escalated: needs a senior analyst soon, still containable.

dangertoneUsed in Dense data
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 Dense data

Breach confirmed: a real loss.

How Dense data uses it​

A status
Use Badge with a subtle fill, an icon and a word
Not A full-strength fill
Subtle fills let many statuses share one table.
Shape of a status badge
Use radius.badge (rectangle)
Not A pill
Rectangles line up in a column.

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.

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

Many statuses share one table; color alone is not enough.

2So Badge
  • ✓uses neutral: New and False positive: not triaged yet, or a finished outcome that is not a failure.
  • ✓uses info: Investigating: an analyst is on it; news, nothing to act on.
  • ✓uses success: Resolved: contained and closed.
  • ✓uses warning: Escalated: needs a senior analyst soon, still containable.
  • ✓uses danger: Breach confirmed: a real loss.
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
Numbers and records

Most of the screen is numbers and records.

2So Badge
  • ✓uses neutral: New and False positive: not triaged yet, or a finished outcome that is not a failure.
  • ✓uses info: Investigating: an analyst is on it; news, nothing to act on.
  • ✓uses success: Resolved: contained and closed.
  • ✓uses warning: Escalated: needs a senior analyst soon, still containable.
  • ✓uses danger: Breach confirmed: a real loss.
It also shapes Sidebar: default Sidebar: outline Empty: default Item: default Item: outline Toggle: default Toggle: outline
3If it changed
5
Badge decisions would reopen

and 44 answers that follow from it: A lot, Scan and compare, People keep their place, and 41 more.

Words​

  • Lead with the object, then the state: "Alert 2041 contained."
  • Use numbers, not words for numbers.
  • One verb per button. No "please", no exclamation marks.
  • Use: Investigate, Filter, Assign, Escalated, Resolved. Avoid: Oops, Awesome, Please, Simply.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Cancel
  • content.action.destroy: Delete
  • content.action.retry: Retry
  • content.action.empty-action: Change filters

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

Dense data 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.

PartIts token and the semantic it aliasesValue
Badge
Cornercomponent.badge.radiusradius.badgevar(--badge-radius)radius.0:0rem
Padding, left and rightcomponent.badge.padding-xspace.gap.tightvar(--badge-padding-x)space.4:0.25rem
Text sizecomponent.badge.font-sizetype.caption.font-sizevar(--badge-font-size)font.size.12:0.75rem
Gapcomponent.badge.gapspace.gap.tightvar(--badge-gap)space.4:0.25rem
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.500:500
Font familycomponent.badge.font-familytype.caption.font-familyvar(--badge-font-family)font.family.ibm-plex-sans:"IBM Plex Sans", system-ui, sans-serif
Neutral
Fill
Changes with theme
component.badge.neutral.backgroundcolor.surface.sunkenvar(--badge-neutral-background)Lightslate.light.100:#EEF1F5Darkslate.dark.100:#262D38
Text
Changes with theme
component.badge.neutral.labelcolor.text.secondaryvar(--badge-neutral-label)Lightslate.light.700:#3D4655Darkslate.dark.500:#C4CBD6
Success
Fill
Changes with theme
component.badge.success.backgroundcolor.status.success.subtlevar(--badge-success-background)Lightgreen.light.100:#DBF7DFDarkgreen.dark.100:#01351A
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)Lightamber.light.100:#FEE8CFDarkamber.dark.100:#3F2B02
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)Lightred.light.100:#FFDBD8Darkred.dark.100:#4C171A
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)Lightblue.light.100:#D3E4FFDarkblue.dark.100:#162C4F
Textcomponent.badge.info.labelcolor.text.info-on-lightvar(--badge-info-label)blue.light.800:#001A4E