# DataDiff (/docs/charts/data-diff)

DataDiff answers "what changed between these two versions?". Each key gets a diverging bar: **removed leftward, added
rightward, both always drawn** on one symmetric shared scale. Net is a mark you can turn on, never a replacement for the
two bars — a +500/−480 churn and a +20/−0 trickle must never look alike.

```tsx
<DataDiff
  data={[
    { key: "users", added: 340, removed: 120 },
    { key: "orders", added: 88, removed: 30 },
    { key: "items", added: 40, removed: 20 },
    { key: "tags", added: 24, removed: 8 },
    { key: "notes", added: 12, removed: 6 },
    { key: "flags", added: 8, removed: 3 },
  ]}
  labels
  title="Schema diff"
  width={200}
  height={72}
/>
```

## Install

```tsx
import { DataDiff } from "@microcharts/react/data-diff";

<DataDiff data={diff} title="Schema diff" />
```

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 table cell per dataset version, a KPI card for a sync or import job, any per-key added/removed audit
  where churn matters.
- **Avoid for** — a plain ranking (MiniBar) or parts of a single whole (SegmentedBar).


## Variants

```tsx
<DataDiff
  data={[
    { key: "users", added: 340, removed: 120 },
    { key: "orders", added: 88, removed: 30 },
    { key: "items", added: 40, removed: 20 },
  ]}
  labels
/>
<DataDiff
  data={[
    { key: "users", added: 340, removed: 120 },
    { key: "orders", added: 88, removed: 30 },
    { key: "items", added: 40, removed: 20 },
  ]}
  net
  label="totals"
/>
```

## Edge cases

```tsx
<DataDiff data={[]} />
```

```tsx
<DataDiff data={[{ key: "a", added: 0, removed: 0 }, { key: "b", added: 0, removed: 0 }]} />
```

An empty `data` array renders an empty chart and reports **"No data."** A non-empty diff where every key is 0/0 still
draws its hairline placeholder ticks and reports **"No changes across 2 keys."** — the keys are named even when nothing
about them changed.


## Why this default

Both directions are always drawn, because net-only diffs hide churn: a table that added 500 rows and dropped 480 is not
the same event as one that added 20 and dropped nothing, even though both net to roughly the same number. One symmetric
scale spans every row so a big change never shrinks to fit a small one, and a key with no change still gets a hairline
tick — the absence of a change is not the absence of the key. Cross-chart comparison goes through a shared `domain`.

## Accessibility

The accessible name states the totals, the key count, and the single largest change — **"+468 added, −170 removed across
3 keys; largest change: users (+220)."** The interactive entry steps the rows and announces each key's added, removed,
and net change.

The interactive entry follows the shared [interaction contract](/docs/accessibility#one-interaction-contract):
arrow keys rove between units on both axes, `Home` and `End` jump to the ends, and a click, tap, `Enter` or
`Space` selects a unit — pinning its readout so it survives blur, until you select it again or press `Escape`.
On touch, a tap pins and a drag scrubs.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `{ key; added; removed }[]` | Per-key change counts — added and removed are non-negative magnitudes. |
| `labels` | `boolean` | In-chart key tags for standalone use (host tables carry keys by default). |
| `net` | `boolean` | A tick at added−removed per row — a summary mark, never the two bars. |
| `order` | `"data" \| "net" \| "magnitude"` | Default 'data' keeps input order (schema order is often meaningful). |
| `label` | `"totals" \| "none"` | 'totals' prints a +added / −removed footer. |
| `maxItems` | `number` | Row cap (default 12); rows beyond it are dropped with a dev warning. |
| `animate` | `boolean` | (interactive) Opt-in entrance motion when the chart mounts client-side — add `import "@microcharts/react/motion"` once. Inert on the server, on hydrated server HTML, and under `prefers-reduced-motion`. |

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).
