# Badge

A small label that shows a status, a count or a category next to other content.

- **Import:** `import { Badge } from "@booleanpress/ui/badge"`
- **Page:** <https://ui.booleanpress.com/components/badge> · @booleanpress/ui 0.1.0

## Usage

A badge is a short piece of text in a pill. It sits beside the thing it describes.

```tsx
import { Badge } from "@booleanpress/ui/badge"

export function Row() {
  return (
    <p>
      ada@example.com <Badge variant="success">Delivered</Badge>
    </p>
  )
}
```

`variant` sets the look: `default`, `secondary`, `outline`, `ghost` and `link` are for categories and counts; `success`, `warning`, `info` and `destructive` are for a status. The status variants (this package's addition to stock) are on the status tokens.

Pass `asChild` and a link to make a badge that goes somewhere: the badge's classes move onto the link, and hover styles apply only then. A badge is not a button: for an action, use `Button`.

## Examples

### Variants

The neutral variants.

```tsx
import { Badge } from "@booleanpress/ui/badge"

export default function BadgeVariants() {
  return (
    <div className="flex flex-wrap justify-center gap-2">
      <Badge>Default</Badge>
      <Badge variant="secondary">Secondary</Badge>
      <Badge variant="outline">Outline</Badge>
      <Badge variant="destructive">Destructive</Badge>
      <Badge variant="ghost">Ghost</Badge>
      <Badge variant="link">Link</Badge>
    </div>
  )
}
```

### Status

The four status variants in a delivery list, each with its word.

```tsx
import { Badge } from "@booleanpress/ui/badge"

export default function BadgeStatus() {
  return (
    <ul className="flex w-full max-w-xs flex-col gap-2 text-sm">
      {[
        { to: "ada@example.com", label: "Delivered", variant: "success" },
        { to: "grace@example.com", label: "Queued", variant: "info" },
        { to: "linus@example.com", label: "Deferred", variant: "warning" },
        { to: "alan@example.com", label: "Failed", variant: "destructive" },
      ].map((row) => (
        <li key={row.to} className="flex items-center justify-between gap-4">
          <span>{row.to}</span>
          <Badge variant={row.variant as "success" | "info" | "warning" | "destructive"}>{row.label}</Badge>
        </li>
      ))}
    </ul>
  )
}
```

### With an icon

A 12 px icon before the text; the badge sizes it.

```tsx
import { CircleCheckIcon, ClockIcon } from "lucide-react"
import { Badge } from "@booleanpress/ui/badge"

export default function BadgeWithIcon() {
  return (
    <div className="flex flex-wrap justify-center gap-2">
      <Badge variant="success">
        <CircleCheckIcon /> Verified
      </Badge>
      <Badge variant="warning">
        <ClockIcon /> Pending
      </Badge>
    </div>
  )
}
```

### As a link

`asChild` puts the badge's look on a link, which keeps its role and address.

```tsx
import { Badge } from "@booleanpress/ui/badge"

export default function BadgeAsLink() {
  return (
    <Badge asChild variant="secondary">
      <a href="#open-tickets">12 open tickets</a>
    </Badge>
  )
}
```

## Accessibility

**Semantics.** A `span`, or the element you pass with `asChild`. It has no role, so a screen reader reads its text in the flow of the sentence.

**Labels.** Its text is its content. A status badge must say the status in words: colour alone fails WCAG 1.4.1. An icon-only badge needs a visually hidden text.

**Focus.** A badge is not focusable and has no keyboard behaviour of its own, so it takes no keyboard rows. A badge made a link with `asChild` is in the tab order and gets the link's keys and the focus ring.

**Known limits.**

- A badge does not announce a change to its text. For a status that changes while people watch, put it in a live region the page owns.

### Keyboard

| Key | Behaviour |
| --- | --- |

## API

### Badge

Renders a `span` and passes it every other prop.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Render the child element instead (usually a link), with the badge's classes merged onto it. |

**Also exported:** `badgeVariants`, the class names of Badge's variants and sizes (`cva`), to give another element the same look.

Every part takes `className`, merged with its defaults by `cn()`, and `ref`, which reaches the element it renders.

**Data attributes:** `data-slot="badge"` (Badge), and `data-variant`.

## Theming

`success` fills with `--success-strong` and `warning` with `--warning`, `info` with `--info`, each with its `-foreground` token for the text. `bui-contrast` checks every pair.

| Token | Used for |
| --- | --- |
| `--accent` | background |
| `--accent-foreground` | text |
| `--border` | border |
| `--destructive` | border, focus ring, background |
| `--foreground` | text |
| `--info` | background |
| `--info-foreground` | text |
| `--primary` | background, text |
| `--primary-foreground` | text |
| `--ring` | border, focus ring |
| `--secondary` | background |
| `--secondary-foreground` | text |
| `--success-foreground` | text |
| `--success-strong` | background |
| `--warning` | background |
| `--warning-foreground` | text |
