# @spark-web/badge — AI Context

## What this is

A status indicator pill that combines a colored dot with a text label. Used to
communicate categorical status on a record or field. The dot is the primary
visual signal; the label provides the text description.

This package also exports `IndicatorDot` — a standalone dot without a label,
used when space is too constrained for a full badge.

## What this is NOT

- Not `StatusBadge` — `StatusBadge` is a colored background pill with no dot;
  use `Badge` when the dot indicator is the primary visual signal
- Not a button or interactive element — display-only
- Not a notification counter — use a different component for numeric counts

## Props interface

### `Badge`

| Prop       | Type                                                                       | Default     | Notes                     |
| ---------- | -------------------------------------------------------------------------- | ----------- | ------------------------- |
| `tone`     | `'accent' \| 'caution' \| 'critical' \| 'info' \| 'neutral' \| 'positive'` | `'neutral'` | Controls the dot color    |
| `children` | `string \| number`                                                         | required    | The label text            |
| `data`     | `DataAttributeMap`                                                         | —           | Test/analytics attributes |

### `IndicatorDot`

| Prop    | Type                                                                       | Notes                                                            |
| ------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `tone`  | `'accent' \| 'caution' \| 'critical' \| 'info' \| 'neutral' \| 'positive'` | required — controls dot color                                    |
| `label` | `string`                                                                   | Supply when the intent isn't conveyed by surrounding text (a11y) |
| `data`  | `DataAttributeMap`                                                         | Test/analytics attributes                                        |

## Token usage

All values from `useTheme()` from `@spark-web/theme`. Never use raw hex, px, or
Tailwind.

### Badge

| Property         | Token / Value                                             |
| ---------------- | --------------------------------------------------------- |
| Display          | `display="inline-flex"` (Box prop)                        |
| Alignment        | `alignItems="center"` (Box prop)                          |
| Background       | `background="surface"` — always white, regardless of tone |
| Border           | `border="standard"` (Box prop)                            |
| Border radius    | `borderRadius="full"` (Box prop)                          |
| Dot-to-label gap | `gap="xsmall"` (Box prop)                                 |
| Height           | `height="xsmall"` (Box prop)                              |
| Horizontal pad   | `paddingX="small"` (Box prop)                             |
| Text size        | `size="xsmall"` (Text prop)                               |
| Text overflow    | `overflowStrategy="nowrap"` (Text prop)                   |

### IndicatorDot

| Property      | Token / Value                                                  |
| ------------- | -------------------------------------------------------------- |
| Dot color     | `theme.color.status[tone]` via `useTheme()` — inline CSS       |
| Dot size      | `8×8px` inline CSS — no Spark size token; documented exception |
| Border radius | `borderRadius="full"` (Box prop)                               |

### IndicatorContainer (internal, not exported)

The dot is wrapped in a container sized to match the text cap-height so the dot
and label align vertically. This uses `theme.typography.text[size].capHeight`
via `responsiveStyles` — do not replicate this in consuming code.

## Tone → dot color mapping

| Tone       | Color source                  |
| ---------- | ----------------------------- |
| `accent`   | `theme.color.status.accent`   |
| `caution`  | `theme.color.status.caution`  |
| `critical` | `theme.color.status.critical` |
| `info`     | `theme.color.status.info`     |
| `neutral`  | `theme.color.status.neutral`  |
| `positive` | `theme.color.status.positive` |

For tone selection rules on admin surfaces, see
`node_modules/@spark-web/design-system/patterns/internal-admin/CLAUDE.md`.

## Badge vs StatusBadge — decision rule

| Signal needed             | Use            |
| ------------------------- | -------------- |
| Dot is the primary signal | `Badge`        |
| Colored pill, no dot      | `StatusBadge`  |
| Standalone dot, no label  | `IndicatorDot` |

For internal-admin surfaces, always use `Badge` in table status columns — see
`node_modules/@spark-web/design-system/patterns/internal-admin/CLAUDE.md`.

## Composition

- `Box` from `@spark-web/box` — outer pill, indicator container, dot
- `Text` from `@spark-web/text` — label at `size="xsmall"`
- `useTheme()` from `@spark-web/theme` — dot color and cap-height alignment

## Do NOTs

- NEVER use raw hex, px, or Tailwind for any visual property
- NEVER change `background="surface"` on `Badge` — the pill is always white;
  tone only controls the dot color
- NEVER use `Badge` when a colored pill is needed — use `StatusBadge`
- NEVER use `tone="pending"` — there is no `pending` tone; use `tone="info"` for
  pending/awaiting states
- NEVER use long label text — text is `nowrap` and will overflow without
  wrapping
- NEVER make `Badge` or `IndicatorDot` interactive — they are display-only
- NEVER omit `label` on a standalone `IndicatorDot` when surrounding text does
  not convey the status meaning
