Skip to content
UI

Badge

A short label that tags a record with an attribute, a category or a count.

@zenoxai/ui/components/badge Markdown
ProductionInternet-facingLinux
<>
  <Badge variant="soft" tone="neutral">
    Production
  </Badge>
  <Badge variant="soft" tone="primary">
    Internet-facing
  </Badge>
  <Badge variant="outline">Linux</Badge>
</>

Usage

import { Badge } from "@zenoxai/ui/components/badge"

export function ExposureTag() {
  return (
    <Badge variant="soft" tone="primary">
      Internet-facing
    </Badge>
  )
}

Use a badge for attributes of a record that the user scans for: an environment, an asset type, a tag, a count. Keep the label to one or two words, in sentence case.

Use something else when the badge would show:

  • The state of a record (new, in progress, resolved, failed). Use StatusBadge. It takes a semantic tone and a label, and keeps the status-to-tone mapping in one place in the app.
  • A severity level (critical, high, medium, low). Use SeverityBadge, which uses the severity scale colors.

Variant and tone

The Zenox variants, soft, solid and outline, take a tone that sets the color. Without a tone they are neutral.

softneutralprimarysuccesswarningdangerinfo
solidneutralprimarysuccesswarningdangerinfo
outlineneutralprimarysuccesswarningdangerinfo
function BadgeMatrix() {
  const variants = ["soft", "solid", "outline"] as const
  const tones = [
    "neutral",
    "primary",
    "success",
    "warning",
    "danger",
    "info",
  ] as const

  return (
    <div className="grid gap-3">
      {variants.map((variant) => (
        <div key={variant} className="flex flex-wrap items-center gap-2">
          <span className="w-14 font-mono text-xs text-text-muted">
            {variant}
          </span>
          {tones.map((tone) => (
            <Badge key={tone} variant={variant} tone={tone}>
              {tone}
            </Badge>
          ))}
        </div>
      ))}
    </div>
  )
}
Variant Use for
soft The default for tags and attributes. Tinted background, low contrast.
solid One badge that must stand out in a dense row, such as “Beta” or “New”. Use sparingly.
outline Secondary tags next to soft ones, and badges rendered as links.
Tone Means
neutral No judgment: an environment, a type, a tag.
primary Highlighted by the product: a feature, a scope.
success Positive or protected: enforced, verified.
warning Needs attention: exposed, expiring.
danger Harmful or broken: compromised, blocked.
info Informational: preview, monitored.

The shadcn variants default, secondary, destructive, ghost and link still exist and ignore tone. Prefer the Zenox variants in new code.

Pill

pill rounds the badge fully. Use it for counts next to a label, and add tabular-nums so the width holds as the number changes.

Open alerts24
<div className="flex items-center gap-2 text-sm">
  Open alerts
  <Badge variant="soft" tone="danger" pill className="tabular-nums">
    24
  </Badge>
</div>

With an icon

Mark the icon with data-icon="inline-start" or data-icon="inline-end"; the badge sizes it to 12px and tightens the padding on that side.

MFA enforcedExposed port 3389
<>
  <Badge variant="outline" tone="success">
    <ShieldCheckIcon data-icon="inline-start" />
    MFA enforced
  </Badge>
  <Badge variant="soft" tone="warning">
    <GlobeIcon data-icon="inline-start" />
    Exposed port 3389
  </Badge>
</>

A badge that filters a list or opens a record renders an <a> through the render prop, with the label inside the link. The outline variant then gets a hover background.

function BadgeAsLink() {
  return <Badge variant="outline" render={<a href="#usage">tag:pci-scope</a>} />
}

Accessibility

  • A badge is plain text. When its meaning depends on the column or the context (“24” next to “Open alerts”), keep that context visible or put it in the label.
  • The tone is a visual hint. The label alone must say what the badge means.

API reference

Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.

Badge

Badge is a short label: a count, a tag, a category. For the state of a record use the StatusBadge pattern, and for a severity level SeverityBadge; both map the domain value to a tone for you. A removable filter is a FilterChip.

PropTypeDefault
pillboolean | null

Fully rounded ends instead of the default small radius.

-
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
tone"info" | "success" | "warning" | "neutral" | "primary" | "danger" | null

Color for the `soft`, `solid` and `outline` variants (`neutral` has no effect on `outline`). The other variants ignore it.

-
variant"link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "soft" | "solid" | null

Style. `default`, `secondary`, `destructive`, `outline`, `ghost` and `link` are complete on their own. `soft` (tinted fill) and `solid` (strong fill) take their color from `tone` and render uncolored without one.

-