# ASCII badge

A status badge set in glyphs, such as [ OK ], < beta > or ┤ v2 ├, with tones from the palette, a fixed width for aligned columns and an optional live dot.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. The asciicn agent skill, for building any ASCII effect on the engine, is at [/.well-known/agent-skills/asciicn/SKILL.md](/.well-known/agent-skills/asciicn/SKILL.md).

> **This is an example, not the only option.** It is one component built on the asciicn engine. Install it when it is what you were asked for. For any other look, don't stretch its props to fit: write your own field on `AsciiShader` ([Write your own](/docs/engine/write-your-own.md)), or draw a CPU grid with `AsciiGrid`, and read this example's source for technique. Its full source is in [https://asciicn.dev/r/ascii-badge.json](https://asciicn.dev/r/ascii-badge.json), under `files[].content`.

## Installation [#installation]

```bash
npx shadcn@latest add https://asciicn.dev/r/ascii-badge.json
```

## Usage [#usage]

```tsx
import { AsciiBadge } from "@/components/asciicn/ascii-badge";

export function BuildStatus() {
  return <AsciiBadge tone="ok">OK</AsciiBadge>;
}
```

`shape` sets the glyphs around the label: `square` (`[ OK ]`), `angle` (`< beta >`), `round` (`( new )`), `pipe` (`┤ v2 ├`) or `inverse`, a solid label in reverse video.

`tone` sets the colour from the `--ascii-color-*` palette: `neutral` is ink, `ok` green, `info` blue, `warn` orange, `error` red and `accent` purple. Pass `color` to use any other colour.

By default the label has one cell of space each side. Set `width` to centre it in at least that many cells instead, so a column of badges lines up: with `width={4}`, `OK` and `WARN` both draw six cells wide, as `[ OK ]` and `[WARN]`.

`dot` puts a `●` before the label that opens out to `◉` and `◎` and back, for states that are live or running.

## Examples [#examples]

### Boot log [#boot-log]

Badges at `width={6}`, so every line of the log starts its text in the same column.

```tsx title="examples/ascii-badge-boot.tsx"
import { AsciiBadge } from "@/components/asciicn/ascii-badge";
import type { AsciiBadgeTone } from "@/components/asciicn/ascii-badge";

const LOG = [
  { badge: "OK", text: "Mounted /data", tone: "ok" },
  { badge: "OK", text: "Started glyph atlas cache", tone: "ok" },
  { badge: "OK", text: "Reached target network", tone: "ok" },
  { badge: "WARN", text: "Clock drift 212 ms, resyncing", tone: "warn" },
  { badge: "FAIL", text: "Failed to start metrics exporter", tone: "error" },
  { badge: "OK", text: "Started web server on :3000", tone: "ok" },
] as const satisfies readonly {
  badge: string;
  text: string;
  tone: AsciiBadgeTone;
}[];

export default function AsciiBadgeBoot() {
  return (
    <ol className="flex w-full max-w-md flex-col gap-1 font-mono text-[13px]">
      {LOG.map((line) => (
        <li key={line.text} className="flex items-baseline gap-[1ch]">
          <AsciiBadge tone={line.tone} width={6}>
            {line.badge}
          </AsciiBadge>
          <span
            className={
              line.tone === "error"
                ? "text-foreground"
                : "text-muted-foreground"
            }
          >
            {line.text}
          </span>
        </li>
      ))}
    </ol>
  );
}
```

### Shapes and labels [#shapes-and-labels]

Each shape once, then badges next to feature names, one with a live dot.

```tsx title="examples/ascii-badge-shapes.tsx"
import { AsciiBadge } from "@/components/asciicn/ascii-badge";

export default function AsciiBadgeShapes() {
  return (
    <div className="flex w-full max-w-md flex-col gap-5">
      <div className="flex flex-wrap items-center gap-x-4 gap-y-3">
        <AsciiBadge tone="ok">OK</AsciiBadge>
        <AsciiBadge shape="angle" tone="accent">
          beta
        </AsciiBadge>
        <AsciiBadge shape="round" tone="info">
          new
        </AsciiBadge>
        <AsciiBadge shape="pipe">v2.4</AsciiBadge>
        <AsciiBadge shape="inverse" tone="warn">
          DEPRECATED
        </AsciiBadge>
      </div>
      <div className="flex flex-col gap-2 text-sm">
        <p className="flex flex-wrap items-baseline gap-x-2">
          <span className="font-medium">Command palette</span>
          <AsciiBadge shape="round" tone="info">
            new
          </AsciiBadge>
        </p>
        <p className="flex flex-wrap items-baseline gap-x-2">
          <span className="font-medium">Team spaces</span>
          <AsciiBadge shape="angle" tone="accent">
            beta
          </AsciiBadge>
        </p>
        <p className="flex flex-wrap items-baseline gap-x-2">
          <span className="font-medium">Live sync</span>
          <AsciiBadge tone="ok" dot>
            live
          </AsciiBadge>
        </p>
      </div>
    </div>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` |  | The label. Short text reads best: OK, beta, v2.4. |
| `shape` | `"square" \| "angle" \| "round" \| "pipe" \| "inverse"` | `"square"` | The glyphs around the label, or reverse video. |
| `tone` | `"neutral" \| "ok" \| "info" \| "warn" \| "error" \| "accent"` | `"neutral"` | Sets the colour: ink, green, blue, orange, red or purple. |
| `color` | `AsciiColor` | `The tone's colour` | Colour override, a palette name or any CSS colour. |
| `dot` | `boolean` | `false` | A pinging ● before the label, for live states. |
| `width` | `number` | `The label plus a cell each side` | Centre the label in at least this many cells, so badges in a column line up. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Glyph cell height: 12, 16 or 20px. |
| `cell` | `number` |  | Glyph cell height in CSS pixels. Overrides size. |

## Notes [#notes]

* The brackets and chevrons are hidden from screen readers, which read the label alone. Write labels that make sense without the colour, such as `FAIL` rather than a red `●`.
* The badge is a `span` of DOM text in `--ascii-font`, so it sits on the text baseline and can be selected and copied.
* The live dot swaps one glyph six times a second, pauses offscreen and in hidden tabs, and holds a solid `●` with reduced motion.