# Badge

> Compact status badge. A CSS component with one class and no JavaScript.

A small badge that shows what state something is in. The colour is set with `data-color`.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/badge/badge.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<span class="lt-badge">In progress</span>
<span class="lt-badge" data-color="success">Approved</span>
<span class="lt-badge" data-color="warning">Attachment missing</span>
<span class="lt-badge" data-color="danger">Rejected</span>
<span class="lt-badge" data-color="neutral">Archived</span>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/badge.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<span {...lt.badge()}>In progress</span>
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If you have the element in a variable,** set them on it with `setAttributes`. That is the way without JSX, whether you just created the element or found it in a page the server sent:

```ts
import { lt, type BadgeColor } from "@lo-tek/interfaces"


const badge = document.createElement("span")
badge.textContent = "Approved"


lt.setAttributes(badge, lt.badge({ color: "success" }))
```

If the colour comes from an API, validate it first:

```ts
const color: BadgeColor = lt.badge.isColor(response.status) ? response.status : "info"


lt.setAttributes(badge, lt.badge({ color }))
```

`lt.setAttributes` also clears attributes from the previous call, so the badge can change colour without the old one staying behind. See [Type-safe use](/type-safe-use.md).

| `data-color` | Used for |
| - | - |
| *(omitted)* | Information, ongoing state. `lt.badge({ color: "info" })` gives the same, without an attribute |
| `success` | Completed, approved, active |
| `warning` | Needs attention, but is not an error |
| `danger` | Rejected, expired, critical |
| `neutral` | Inactive, archived, unknown |

## In a list

The badge usually sits next to what it describes. Here in a [List](/components/list.md) with dividers between the rows:

**Plain HTML**

```html
<ul class="lt-list" data-variant="divided">
<li>Invoice 2026-0481 <span class="lt-badge" data-color="success">Paid</span></li>
<li>Invoice 2026-0482 <span class="lt-badge" data-color="danger">Overdue</span></li>
</ul>
```

If the badge should sit at the right of the row, the app’s layout decides that, with `display: flex` and `justify-content: space-between` on the `li` element.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-badge` | The badge itself. The colour comes from `data-color`. |

| Variable | Default |
| - | - |
| `--lt-badge-padding` | `var(--lt-spacing-0-5) var(--lt-spacing-2)` |
| `--lt-badge-radius` | `var(--lt-spacing-4)` |

See [Customising](/customising.md) for how the variables and the layer work.

## Accessibility

- Colour alone says nothing to a screen reader. The text has to carry the meaning: “Rejected”, not just a red dot.
- `<span>` inside a line of text, `<div>` when the badge stands alone.
- If the badge changes while the page is otherwise still, put `role="status"` and `aria-live="polite"` on the element around it.
