Skip to content

The library's inline pill: status labels, counts and removable tokens.

import { BbBadge } from 'bitboss-ui';

On this page

Use it for

BbBadge is a small inline pill: a status label (Active, Beta), a short count, a token the user can dismiss.

Use something else when

  • BbIndicator, when the marker belongs on top of something else: an unread count on a bell, a presence dot on an avatar
  • BbTag, when the token is an input people type free-form values into
  • BbButton, when it is a standalone action

Also see: Design language.

Coming from v2

Two v2 names land here. The v2 BbBadge, the count anchored to an element, is now BbIndicator: rename the tag and move content to text. BbChip is this badge with clearable, which you now have to write yourself.

Passthrough

Hover or tap a part to outline it. The toggles turn on loading, errors and warnings where the component has them; only parts get a row.

Heads up

Status labels

Write the label inside the badge; there is no text or content prop. Map each state to one variant and one icon in a single table, so colour is never the only signal.

ORD-2026-0511€199.00Pending
ORD-2026-0507€627.90Pending
ORD-2026-0480€1,286.80Processing
ORD-2026-0491€958.90Shipped
ORD-2026-0485€84.50Cancelled
ORD-2026-0469€249.00Delivered
ORD-2026-0421€899.00Refunded

A badge is inert until you add clearable or a BbBadgeButton.

Variants and sizes

variant picks the tone of the pill: primary, secondary, outline, destructive. primary is the default. Sizes run from xs to 2xl, and md, the default, is the one meant for a line of running text.

primary
NewxsNewsmNewmdNewlgNewxlNew2xl
secondary
DraftxsDraftsmDraftmdDraftlgDraftxlDraft2xl
outline
v2.4xsv2.4smv2.4mdv2.4lgv2.4xlv2.42xl
destructive
OverduexsOverduesmOverduemdOverduelgOverduexlOverdue2xl
PaidContinueVerifiedBeside an sm button: xl

Keep destructive for what is actually wrong. There is no success variant, and an unregistered name colours nothing, so register the tones you need. variant="none" drops the variant class entirely, for pills you colour yourself.

Beside a control the badge runs larger than the button it pairs with: lg next to xs, xl next to sm, 2xl next to md.

Icons

prepend:icon and append:icon put an icon beside the label. With icon the badge goes icon-only and the slot becomes its accessible name, so keep writing the label. An empty one is an error for npx bitboss-ui check and the ESLint rule require-accessible-name.

The slots named after those props (#icon, #prepend:icon, #append:icon) replace them inside the icon part, so pt:icon, --icon-size and the loading spinner still apply. Their scope is the badge's states, { loading, activeLink, exactActiveLink }, so a chip that links to a page can show a solid glyph while that page is open.

Removable tokens

clearable adds a trailing clear button and emits click:clear when it is pressed.

Filtered byFurnitureDisplaysAudio & Video

The badge does not remove itself: taking the item out of your own state is your job. The × is named "Remove" plus the badge's text, so a chip reading Italy announces "Remove Italy" with no wiring. A clearable-label is the ×'s whole name, on any body: write the full phrase, not a verb. An append:icon shares the trailing slot with the ×, which then shows only on hover or focus, so lead removable chips with prepend:icon.

Clickable badges

To make the pill's body clickable, slot a BbBadgeButton as a direct child of the default slot. The clear button stays beside it, with its own tab stop.

Press the label to change the value, the × to drop the filter. They are two tab stops.

With a BbBadgeButton in the body the × is named by the bare verb, "Remove", so give it a clearable-label that says what goes. BbBadgeButton composes BbBaseButton, so it also takes href, to, target, rel and disabled. On Inertia, method needs href: only href becomes a visit, and to is a router link.

A link body's slot gets { activeLink, exactActiveLink }, and the state reaches the whole chip: pt:root:active-link and the icon slots. Whatever renders outside the button (the badge's root, and the × side of a clearable badge) gets it only once the page hydrates; the label and the leading icon have it in the server HTML.

Changelog is disabled until the release ships: no href, out of the tab order.

Nothing warns you about two mistakes. Wrapping the BbBadgeButton in another element duplicates the label. Slotting a plain <button> instead nests it inside the badge's own button once the badge is clearable.

Loading

loading swaps a spinner in for the leftmost icon: the trailing one when that is the only icon, a leading slot of its own when there are none.

TCK-1042 · Printer on floor 3 is offline

A loading badge ignores clicks on its BbBadgeButton: your @click does not fire, a link does not navigate and the body leaves the tab order. Set loading on the one badge whose action is saving, and a second press cannot run it twice.

Custom tones

For a tone that recurs across the product, register a variant in the plugin config instead of colouring pills one at a time.

ts
// nuxt.config.ts
export default defineNuxtConfig({
    bitboss: { badgeVariants: ['soft-green'] },
});

The registered name joins the TypeScript union behind variant and gives you a .bb-badge--soft-green hook. You write the CSS, setting the two custom properties the built-in variants drive. Mix them from a theme token, so the pill follows dark mode and a retuned palette.

css
.bb-badge.bb-badge--soft-green {
    --bg: color-mix(in oklab, var(--bb-success) 15%, var(--bb-panel));
    --fg: color-mix(in oklab, var(--bb-success) 55%, var(--bb-text));
}

The same class reaches past color: --bw with --border-color draws a border, --r rounds the pill, --fs and --px set the label size and side padding, and --ring-color with --ring-size style the focus ring of a clickable badge.

For a one-off accent, override the same properties inline: :style="{ '--bg': 'var(--bb-info)', '--fg': 'var(--bb-info-fg)' }". With a colour of your own, check the contrast yourself.

When the colours come from data, such as labels each workspace colours its own way, there is no name to register. Set variant="none": the badge renders no variant class and you paint it with --bg and --fg. Until you set them it keeps the base primary colours.

BackendNeeds designGood first issueBlocked
Coming from v2v2 stylesheets

.bb-chip selectors become .bb-badge, the label span is .bb-badge__text and the × is .bb-badge__clear (it was __clear-button). The pill now holds two sides, .bb-badge__body and .bb-badge__trailing, so a direct-child selector such as .bb-badge > .bb-badge__text has to become a descendant one. npx bitboss-ui check flags each stale .bb-* selector and names the class to use.