# TallyMarks (/docs/charts/tally-marks)

TallyMarks answers "how many?" the way a human actually counts — in four-and-strike clusters of five. The count reads
back exactly: no scale to calibrate, no color to decode. Past `total` the marks stop growing and a `+N` numeral tells
the truth, so a cell never blows out its width. Marks are never resized to fit — width grows with the count until the
cap, then the numeral takes over.

```tsx
<TallyMarks value={23} title="Signatures" height={20} />
```

## Install

```tsx
import { TallyMarks } from "@microcharts/react/tally-marks";

<TallyMarks value={23} title="Signatures" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## When to use it

- **Good for** — a small running count in a sentence or cell, a live event or score counter, or an editorial
  hand-tallied context.
- **Avoid for** — large magnitudes (MiniBar), trends over time (Sparkline), or proportions (Progress).


## Variants

```tsx
<TallyMarks value={17} pen="drawn" />
<TallyMarks value={38} total={20} />
```

## Edge cases

```tsx
<TallyMarks value={0} />
```

```tsx
<TallyMarks value={-5} />
```

```tsx
<TallyMarks value={5000} total={5000} />
```


## Why this default

The ruled pen is the default because product tables want precision first — evenly ruled strokes count back fastest. The
`drawn` pen adds a seeded, deterministic jitter (same count always renders identically, on the server and after
hydration) for the editorial voice, and it only perturbs how each stroke is drawn — the count is never touched. Past
`total`, the default `overflow="numeral"` appends a `+N` so the true total survives even when the marks can't;
`overflow="clamp"` suppresses the numeral for dense columns, and the accessible name still carries the exact count.

## Accessibility

The accessible name is the exact count — **"17 counted."** — always the true value, even when the marks overflow to a
`+N` numeral or clamp. The interactive entry announces the new total through a polite live region on change and draws
newly added marks in with a brief, reduced-motion-gated sweep. A count has no sub-parts, so focus reads the summary and
there is no cursor to move.

This chart is a single unit, so there is nothing to rove between: a click, tap, `Enter` or `Space` selects it
and fires `onSelect`, and no selection stays pinned. That is the scalar half of the shared
[interaction contract](/docs/accessibility#one-interaction-contract).

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `value` (required) | `number` | The count. Floored; negatives clamp to 0. |
| `total` | `number` | Marks drawn before overflow (default 25). |
| `overflow` | `"numeral" \| "clamp"` | numeral appends +N; clamp stops drawing. The summary always keeps the true count. |
| `pen` | `"ruled" \| "drawn"` | Hand-drawn jitter for editorial contexts. |

Plus the shared grammar — `data`, `domain`, `color`, `title`, `summary`, `format` — and the layout props (`width`, `height`, `className`, `style`) that every chart accepts. Interactive entries also share `animate` and `live`, and — wherever a chart has more than one navigable unit — `onActive`, `onSelect`, `selectedIndex` and `defaultSelectedIndex`; and — wherever the chart shows a hover value — `readout`. See [the shared grammar](/docs/quickstart#the-shared-grammar).
