# Badge

> A small label for a status, count or category.

- Import: `import { Badge } from '@thekestongroup/ui'`
- Group: Element
- Live example: https://ui.keston.co/storybook/?path=/story/components-element-badge--default
- Source: https://github.com/thekestongroup/ui/blob/main/src/components/Badge/Badge.vue

## When to use

- Showing a status ("Paid", "Overdue"), a count (unread messages) or a category ("Year 9") next to the thing it describes.

## When not to use

- Anything people can press (use Button).
- Long messages or explanations (use text, or a callout).

## Anatomy

| Part | Required | Notes |
|---|---|---|
| container | Yes | Pill shape with a 1px border. |
| label | Yes | Short text or a number. |
| leading | No | e.g. an icon. |
| trailing | No | e.g. an icon. |

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| color | basic \| primary \| red \| green \| blue \| yellow | basic | Colour, by meaning (see Variants). |
| size | sm \| md \| lg | md | |

## Variants

| Color | Use for | Example |
|---|---|---|
| basic | Neutral information, categories, counts | Year 9, 28 students |
| primary | Emphasis | New |
| green | Positive, done | Paid, Enrolled |
| blue | Informational, ongoing | In progress |
| yellow | Needs attention soon | Due soon |
| red | A problem | Overdue |

## Sizes

| Size | Height | Padding (x) | Gap | Icon size | Text style |
|---|---|---|---|---|---|
| sm | spacing 5 (20px) | spacing 1.5 | spacing 1 | 12px | xs, bold |
| md | spacing 6 (24px) | spacing 2 | spacing 1 | 14px | xs, bold |
| lg | spacing 7 (28px) | spacing 2.5 | spacing 1.5 | 16px | sm, bold |

## States

Not interactive: one state only.

## Content guidelines

- One or two words, sentence case ("Due soon", not "DUE SOON").
- Never wraps; keep it short rather than truncating.

## Accessibility

- Plain text (`<span>`), read in place with the surrounding content.
- Colour must not be the only signal: the text says what the colour means.
- White text on every solid colour meets WCAG AA (4.5:1 or more), except yellow, which uses black text (12:1).

## Platform adaptation

| Platform | Implementation | Differences |
|---|---|---|
| Web / desktop (Vue) | `Badge.vue` | — |
| iOS (SwiftUI) | — | Capsule-shaped Text. |
| Android (Compose) | — | Badge / AssistChip (non-clickable). |

## Tokens used

| Token | Used for |
|---|---|
| color white, black | basic background, text |
| color black (15%) | border |
| color primary, green, blue, yellow, red | solid backgrounds (black text on yellow) |

## Do / Don't

| Do | Don't |
|---|---|
| Pick the colour by meaning. | Use colours for decoration, or make them clickable. |

## API (from the source)

The component's exact props, model, events, slots and types, with their documentation comments.

```ts
// Badge.vue
/**
 * A small label for a status, count or category, e.g. "Active", "3", "Year 9".
 * Not interactive: for something people can press, use a Button.
 *
 * Slots: default (the text), leading and trailing (e.g. an icon).
 */
export interface BadgeProps {
  /**
   * Colour, by meaning:
   * - basic: neutral information, e.g. a category or count
   * - primary: emphasis, e.g. "New"
   * - green: positive / done, e.g. "Paid"
   * - blue: informational, e.g. "In progress"
   * - yellow: needs attention, e.g. "Due soon"
   * - red: a problem, e.g. "Overdue"
   *
   * Colour alone doesn't carry meaning for everyone, so the text should say
   * it too.
   */
  color?: 'basic' | 'primary' | 'red' | 'green' | 'blue' | 'yellow'
  size?: 'sm' | 'md' | 'lg'
  class?: HTMLAttributes['class']
}

defineSlots<{
  default?(): unknown
  leading?(): unknown
  trailing?(): unknown
}>()
```
