Badge

A small count or status dot pinned to the corner of whatever it wraps, for things that need noticing without being read.

Usage

When to reach for Badge, what each of its axes is for, and the decisions it leaves to you.

When to use

A Badge is a small count or colored dot pinned to what it decorates. It is the loudest mark the kit draws, so use it to pull the eye to something unread, unseen or down.
  • An unread count on a control that already exists: a bell, an inbox link, a tab label.
  • A health or presence dot beside a name, with the word in text.
  • A standalone count in navigation, which disappears when it reaches zero.
Use something else when
  • The label is a word, not a count. That is a Tag. The badge pill is shaped for digits.
  • It hangs over a card's corner. That is a ribbon. Import Ribbon from @/components/ui/ribbon instead of using Badge.Ribbon, and see its own page.
  • Use Avatar's indicator for presence dots. offset moves the count by a fixed number of pixels, which stops fitting when the avatar size changes. Avatar's indicator prop puts the dot on its rim at any size, and takes a childless <Badge />.

A count or a dot

A count says how many. A dot only says that something is there.
  • Use count when the number changes what the reader does: 3 unread and 47 unread are different messages.
  • Use dot when it does not: a “new since you last looked” mark, a nav item with something waiting, an edited field.
  • dot wins over count when both are set. The number is not shown or announced, so do not set both.
  • count takes any node, so an icon or a short word works. A word may need less inline padding, set through classNames.
  • size applies to counts only. A status dot ignores it. To shrink a presence dot, scale what it sits on, or change Badge's tokens in your theme.

Capping the number

overflowCount is the largest number shown as is. Past it the badge shows the cap with a plus, so the default of 99 turns 100 into 99+.
  • A cap says the exact figure does not matter here. If the reader has to act on 132 rather than “a lot”, raise the cap or drop it.
  • Pick the cap from the space you have. 99+ is three characters wide, and in a dense sidebar 9 is often the better cap.
  • Name the count. The hover tooltip is the bare number, uncapped. Set title to a sentence like “17 unread messages”, or to null to remove it when a label already says what is counted.
  • Use one cap per surface. Two counts in one column capped differently read as two different scales.

Zero

A zero hides the badge. A count of 0 shows nothing and takes no space unless you set showZero. That is usually right: nobody needs to read “0 unread”.
  • Set showZero in a table or dashboard where zero is the result (0 failed checks), or where a disappearing badge would shift a fixed row.
  • Leave it off for unread counts. A badge that is always there stops meaning “look here”.
  • A zero count also hides a dot set beside it. A bare dot with no count always shows.
  • The badge zooms in and out as it appears and disappears, and the number rolls when it changes. That reads well in a list that counts down one row at a time, less so when the layout shifts at the same moment.

Status, and its text form

status takes five states (success, processing, default, error, warning) and shows them as a dot, with text as the label beside it. A count says how many, a status says what kind.
  • Use it for a state worth scanning a column for: a service that is up, a job that is running, a deploy that failed.
  • A count replaces the status dot. While there is a count to show, the status dot is hidden, so do not set both and expect them side by side.
  • text makes it readable. A bare dot is only a color, which means nothing to a reader who cannot tell the hues apart.
  • status="default" means no status: a gray dot. Use it for “not deployed” or “not applicable”, never for “fine”. antd paints it a translucent gray, so a photo or a colored surface shows through. The kit paints colorStatusDefault instead, the same gray on a card, and falls back to antd's color when a theme leaves the token out.
  • emphasis="strong" colors the label. It works on a status with text, and does nothing on a count. status="default" keeps its normal label color, and a preset label is a shade darker than its dot so it stays readable.

Color, and what it is allowed to mean

status and color are two props. status takes the five states and pairs with text. color takes antd's presets (blue, green, gold and the rest), a palette from your theme (the default theme adds amber, emerald, teal, sky, indigo, violet, fuchsia, rose and grays like slate and zinc), or any CSS color, and wins over status. emphasis decides whether the color reaches the label.
  • Presets and palettes follow the theme in both modes, and a palette you add to your theme works by name too. A hex color stays the same in dark mode.
  • A count is not stuck on red. color recolors counts and dots too. The default red is colorError, so it follows your theme.
  • Spend color on meaning, not decoration. Once two badges on a page differ in color for no reason, neither color says anything.
  • Never let color carry the meaning alone. Pair it with the count, the word in text, or the label of what it decorates.

Standalone or wrapping

Children decide the form. With children, the count sits on their corner. Without them it renders inline, and offset does nothing.
  • Wrap when the badge belongs to one object: an avatar, a bell, a thumbnail, a card.
  • Stand alone when it belongs to a row: a count at the end of a sidebar link, inside a tab label or in a list header, where it lines up with its neighbors.
  • Badge adds no interactivity, so what makes it clickable is what you put inside it.
  • Put the Badge around a control. Wrapping a Button keeps its focus ring, disabled state and name. Wrapping the Badge in a link makes both one larger target instead.

Offset

offset is an [x, y] pair from the default corner, and only works when the Badge wraps something.
  • On a round child the count sits outside the curve, so you pull it in. The right amount depends on the size, so an offset tuned for a 48px avatar is wrong on a 32px one.
  • x is always pixels. y also takes a string with units, like "0.5rem".
  • x follows the writing direction, so an RTL layout needs no second value.