Components · Feedback indicators

Badge

A pill-shaped label that carries one piece of metadata. Six status tones, three sizes, optional leading icon or status dot. Reach for it whenever a row, card, or table cell needs a small piece of grippable context.

Documentedby Derek Fidler
Step

Default — neutral

Overview

Badges sit one tier below status pills. Where a StatusPillclaims a card or row's headline status, a Badge tags a piece of metadata: a count, a tag, a small qualifier next to a heading. The shape — full-rounded, tinted-on-tinted — is the same; the role is quieter.

Pick the right component

Badge for inline metadata (tags, counts, small qualifiers). StatusPill for the headline status of a row or card. RiskBadge for the three-level risk signal (low/medium/high) on the prototypes catalog. They share visual DNA but communicate different things.

Tones

Seven variants. Six are status-driven (neutral, danger, warning, success, info, discovery); the seventh is outline — a bordered transparent variant for surfaces where another tinted pill would fight the page.

  • Stepneutral

    The default. Tags, generic metadata, dense list-row labels.

  • Stepdanger

    Destructive states — killed prototypes, declined transactions.

  • Stepwarning

    Pending decisions, building states, near-threshold metrics.

  • Stepsuccess

    Demo-ready, paid, healthy services.

  • Stepinfo

    Neutral status, links, advisories.

  • Stepdiscovery

    Beta, what's new, content the user hasn't seen before.

  • Stepoutline

    When the surface beneath shouldn't bear extra chroma — bordered, transparent fill.

Sizes

Three sizes. md is the default; sm for dense rows or count badges; lgwhen the badge is a card's headline qualifier.

Step

Small

size="sm"

Dense rows, table cells, beside small text.

Step

Medium

size="md"

The default. Catalog rows, prototype detail meta, status callouts.

Step

Large

size="lg"

Hero surfaces, marketing tiles, anywhere a single badge headlines a card.

Compositions

Three composition patterns cover almost every Badge moment. Pick the one the data calls for; don't mix two — a leading icon and a dot together is visual noise.

10%Step

Leading icon

Pass leadingIconfor a glyph before the label — trend arrows, info pictograms, anything the variant's tone doesn't already carry.

StepLivePending

Dot

Pass dotfor a small filled circle in the variant's foreground tone — used for status badges where the dot reinforces the colour for users with reduced colour perception.

11299+

Count badges

Use size="sm" with a short numeric label — notification counts, unread totals. Cap at 99+ so the pill stays one line.

internalstaginglow risk

Outline (tag pattern)

Bordered, transparent fill. Use on already-tinted surfaces (an accent section background) where another tinted pill would fight for attention.

Anatomy

Three named parts. Only the label is required — leading icon and dot are opt-in.

Demo-ready
  1. Container

    Full-rounded pill (radius 9999). Carries the variant background and, on outline, a 1 px border.

  2. Leading slot

    Optional. Either an icon (leadingIcon prop) or a coloured dot (dotprop). Inherits the variant's text colour via currentColor.

  3. Label

    Inter Tight Semibold. Sentence case. Single line — let it truncate at the parent if the layout is constrained.

Behavior

  • Static — not a button. Badges don't take click handlers. They're labels. If the user needs to act on it, wrap in a Link or use a different component.
  • One badge tells one thing. A pile of three badges next to a row title means three things compete for the eye — usually the row needs a structural redesign, not more badges.
  • Icon or dot, not both. The leading slot fits one piece of furniture. Two reads as busy.
  • Counts cap at 99+. Three-digit counts force the pill into a second line or break the layout. Display 99+ when the underlying number exceeds 99 and link to the underlying list.

Accessibility

  • Don't carry meaning in colour alone. Every badge is a small text label first. The variant tone is reinforcement, not the only signal — colour-blind users read the label.
  • Leading icon is decorative. The component sets aria-hidden="true" on the icon slot — assistive tech reads the label, not the glyph. If the icon carries unique meaning, encode it in the label too.
  • Counts use the underlying number in the accessible name when wrapping the badge in a control: e.g. <Link aria-label="Inbox · 12 unread"> so screen readers don't announce just “12”.
  • Contrast is calibrated.Every variant's text/background combination meets WCAG AA at the default badge size. Smaller sizes drop below the recommended density for body text but keep AA for “large text” under WCAG 2.2 — fine for short labels and counts, less suitable for full sentences.

Code

tsx

import { Badge } from "@flatpay-dk/ui";

// Default — neutral, md
<Badge>Step</Badge>

// Status-driven tones
<Badge variant="success">Demo-ready</Badge>
<Badge variant="warning">Building</Badge>
<Badge variant="danger">Killed</Badge>
<Badge variant="info">Note</Badge>
<Badge variant="discovery">Beta</Badge>

// Outline — for tinted surfaces
<Badge variant="outline">internal</Badge>

// Sizes
<Badge size="sm">1</Badge>
<Badge size="lg">Demo-ready</Badge>

// With a leading icon
<Badge variant="neutral" leadingIcon={<TrendUpIcon />}>10%</Badge>

// With a status dot
<Badge variant="success" dot>Live</Badge>

// Count badge
<Badge size="sm" variant="discovery">12</Badge>
<Badge size="sm" variant="danger">99+</Badge>

Best practices

LivePending

Do

Use one badge per data point. The dot reinforces the colour for accessibility.

LiveStagingPendingBetainternal

Don't

Don't pile badges. Three or more next to a row title means the row needs structural design, not more pills.

1299+

Do

Cap counts at 99+. Two characters max keeps the pill on one line.

Demo-ready

Don't

Don't combine an icon and a dot. Pick one piece of leading furniture.

Props

PropTypeDefaultDescription
variant"neutral" | "danger" | "warning" | "success" | "info" | "discovery" | "outline""neutral"Surface tone. Six status-driven options plus an outline for tinted contexts.
size"sm" | "md" | "lg""md"Vertical density. sm for dense rows + count badges; lg for hero qualifiers.
leadingIconReactNodeOptional icon rendered before the label. aria-hidden by default — encode meaning in the label.
dotbooleanfalseRender a 6 px filled dot in the variant's text colour before the label. Mutually exclusive with leadingIcon.
...restHTMLAttributes<HTMLSpanElement>Standard span attributes (className, id, data-*, title) pass through.