Skip to main content

Badge

Atombeta@macaw-ds/ui · since 0.1.0

A short, non-interactive status label such as Paid, Overdue or Draft. Not a button, not a counter.

Import

import { Badge, badgeVariants } from '@macaw-ds/ui';

Props

PropTypeDefaultDescription
tone"neutral" | "success" | "warning" | "critical" | "info" | "accent"neutral

Meaning. success for settled or active, warning for pending or attention, critical for failed or overdue, info for informational, accent for highlighted, neutral for draft or archived.

variant"soft" | "solid" | "outline"soft

Emphasis. soft (tinted) is the default in tables; solid for a single prominent status on a detail page; outline for the quietest option.

size"sm" | "md"md

20 or 24 px tall. sm inside dense table rows.

dotbooleanfalse

Leading dot in the tone colour, for live or state indicators.

Accessibility: Decorative (aria-hidden). The text must still say the state.

childrenReactNodePaid

The status word or two.

Slots

Named parts you pass content into.

  • children

Tokens used

Every value this component renders comes from one of these tokens.

TokenLightDark
badge.radius

component · dimension

9999px
9999px
badge.height.sm

component · dimension

20px
20px
badge.height.md

component · dimension

24px
24px
color.status.success-bg

semantic · color

oklch(0.97 0.03 152)
oklch(0.24 0.05 152)
color.status.success-fg

semantic · color

oklch(0.37 0.1 152)
oklch(0.88 0.1 152)
color.status.success-solid

semantic · color

oklch(0.44 0.12 152)
oklch(0.68 0.15 152)
color.status.success-solid-fg

semantic · color

oklch(1 0 0)
oklch(0.11 0.01 250)
color.status.success-line

semantic · color

oklch(0.6 0.15 152)
oklch(0.5 0.14 152)
color.status.warning-bg

semantic · color

oklch(0.98 0.03 80)
oklch(0.25 0.05 50)
color.status.warning-fg

semantic · color

oklch(0.41 0.11 50)
oklch(0.9 0.12 80)
color.status.critical-bg

semantic · color

oklch(0.97 0.02 27)
oklch(0.25 0.07 27)
color.status.critical-fg

semantic · color

oklch(0.39 0.14 27)
oklch(0.88 0.08 27)
color.status.info-bg

semantic · color

oklch(0.97 0.02 230)
oklch(0.24 0.05 230)
color.status.info-fg

semantic · color

oklch(0.38 0.09 230)
oklch(0.88 0.07 230)
color.status.neutral-bg

semantic · color

oklch(0.965 0.003 250)
oklch(0.21 0.012 250)
color.status.neutral-fg

semantic · color

oklch(0.29 0.012 250)
oklch(0.925 0.005 250)
color.status.accent-bg

semantic · color

oklch(0.97 0.02 262)
oklch(0.24 0.08 262)
color.status.accent-fg

semantic · color

oklch(0.38 0.15 262)
oklch(0.88 0.08 262)
text.size.label-sm

semantic · dimension

0.75rem
0.75rem
text.size.caption

semantic · dimension

0.6875rem
0.6875rem

Eject

Ejecting copies the source into your repo and records it in .macaw/ejected.json, so the fork stays visible. The same file is served as a shadcn-compatible registry item.

With the MACAW CLI
npx @macaw-ds/cli add badge --eject
With shadcn
npx shadcn@latest add https://macaw-design-system.vercel.app/r/badge.json

Bundle budget: 2,500 bytes gzipped, enforced by size-limit in CI.

Manifest

registry/manifests/badge.json, the contract the playground, CLI, plugin and MCP server read.

{
  "name": "Badge",
  "slug": "badge",
  "package": "@macaw-ds/ui",
  "status": "beta",
  "since": "0.1.0",
  "level": "atom",
  "category": "feedback",
  "purpose": "A short, non-interactive status label such as Paid, Overdue or Draft. Not a button, not a counter.",
  "description": "Status labels for records and rows. Six tones map to the status colour tokens; three variants trade emphasis for density. The text carries the meaning so colour is never the only signal.",
  "exports": [
    "Badge",
    "badgeVariants"
  ],
  "props": {
    "tone": {
      "type": "enum",
      "values": [
        "neutral",
        "success",
        "warning",
        "critical",
        "info",
        "accent"
      ],
      "default": "neutral",
      "required": false,
      "description": "Meaning. success for settled or active, warning for pending or attention, critical for failed or overdue, info for informational, accent for highlighted, neutral for draft or archived.",
      "control": "select"
    },
    "variant": {
      "type": "enum",
      "values": [
        "soft",
        "solid",
        "outline"
      ],
      "default": "soft",
      "required": false,
      "description": "Emphasis. soft (tinted) is the default in tables; solid for a single prominent status on a detail page; outline for the quietest option."
    },
    "size": {
      "type": "enum",
      "values": [
        "sm",
        "md"
      ],
      "default": "md",
      "required": false,
      "description": "20 or 24 px tall. sm inside dense table rows."
    },
    "dot": {
      "type": "boolean",
      "default": false,
      "required": false,
      "description": "Leading dot in the tone colour, for live or state indicators.",
      "a11y": "Decorative (aria-hidden). The text must still say the state."
    },
    "children": {
      "type": "node",
      "default": "Paid",
      "required": false,
      "description": "The status word or two."
    }
  },
  "slots": [
    "children"
  ],
  "tokens": [
    "badge.radius",
    "badge.height.sm",
    "badge.height.md",
    "color.status.success-bg",
    "color.status.success-fg",
    "color.status.success-solid",
    "color.status.success-solid-fg",
    "color.status.success-line",
    "color.status.warning-bg",
    "color.status.warning-fg",
    "color.status.critical-bg",
    "color.status.critical-fg",
    "color.status.info-bg",
    "color.status.info-fg",
    "color.status.neutral-bg",
    "color.status.neutral-fg",
    "color.status.accent-bg",
    "color.status.accent-fg",
    "text.size.label-sm",
    "text.size.caption"
  ],
  "a11y": {
    "role": "none (a span with text)",
    "focusable": false,
    "keyboard": [],
    "name": "The text content. A badge has no role; it reads as part of the surrounding text.",
    "notes": [
      "Every tone pairing meets 4.5:1 for text in both themes.",
      "Colour reinforces the word; it never replaces it. \"Overdue\" in critical, not a red dot alone.",
      "Badges are not interactive. For a filter chip or a removable tag, a different component is needed (not in the system yet)."
    ]
  },
  "budget": {
    "gzip": 2500
  },
  "rules": [
    "The label is a word or two that states the status in plain language.",
    "Tone follows meaning, not decoration: critical means failed or overdue, never \"important\".",
    "One badge per status; do not stack badges to combine meanings."
  ],
  "dos": [
    "Use soft badges in tables and solid on a record's header.",
    "Use dot with neutral for \"Draft\" and with success for \"Active\"."
  ],
  "donts": [
    "Do not make badges clickable; they have no role and no focus style.",
    "Do not use badges as counters; a count is Text numeric."
  ],
  "examples": [
    {
      "name": "Default",
      "props": {
        "children": "Paid",
        "tone": "success"
      }
    },
    {
      "name": "Overdue",
      "props": {
        "children": "Overdue",
        "tone": "critical"
      }
    },
    {
      "name": "Solid",
      "props": {
        "children": "Refunded",
        "tone": "info",
        "variant": "solid"
      }
    },
    {
      "name": "Outline",
      "props": {
        "children": "Draft",
        "tone": "neutral",
        "variant": "outline"
      }
    },
    {
      "name": "With dot",
      "props": {
        "children": "Active",
        "tone": "success",
        "dot": true
      }
    },
    {
      "name": "Small",
      "props": {
        "children": "Pending",
        "tone": "warning",
        "size": "sm"
      }
    }
  ],
  "registryDependencies": [],
  "dependencies": [
    "class-variance-authority"
  ],
  "related": [
    "text"
  ]
}