# NetFlow (/docs/charts/net-flow)

Money came in, money went out, and the number you act on is what's left. NetFlow draws inflow as an area above a zero
baseline and outflow mirrored below it on **one shared magnitude scale**, never independently scaled to balance the
picture, with the net line (`in − out`) on top. Gross and net answer different questions, and one cell answers both.
Both areas anchor at zero, the net line is a plain `in − out` and is never smoothed, and its sign is stated in the
label's **text**, so direction is never carried by color alone.

```tsx
<NetFlow
  data={[
    { in: 42, out: 31 },
    { in: 38, out: 35 },
    { in: 45, out: 29 },
    { in: 40, out: 44 },
    { in: 52, out: 38 },
    { in: 48, out: 41 },
    { in: 55, out: 36 },
    { in: 50, out: 47 },
    { in: 58, out: 39 },
    { in: 44, out: 52 },
    { in: 60, out: 41 },
    { in: 57, out: 43 },
  ]}
  format={(n) => `${n}k`}
  label="last"
  title="Monthly cash flow"
  width={260}
  height={30}
/>
```

## Install

```tsx
import { NetFlow } from "@microcharts/react/net-flow";

<NetFlow data={months} title="Monthly cash flow" />
```

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

## Try it

```tsx
import { NetFlow } from "@microcharts/react/net-flow/interactive";

<NetFlow
  data={months}
/>
```

## When to use it

Use it for cash flow per account row, in vs out (signups vs churn) in a KPI card, and any in-vs-out where the net is the
decision. For a single net series use Sparkline; for one period's split use Delta or SegmentedBar.

## Sizing

**mirrored bars for few months**

```tsx
<NetFlow
  data={[
    { in: 42, out: 31 }, { in: 38, out: 35 }, { in: 45, out: 29 }, { in: 40, out: 44 },
    { in: 52, out: 38 }, { in: 48, out: 41 }, { in: 55, out: 36 }, { in: 50, out: 47 },
    { in: 58, out: 39 }, { in: 44, out: 52 }, { in: 60, out: 41 }, { in: 57, out: 43 },
  ]}
  mode="bars"
/>
```

**debt paydown (outflow is the goal)**

```tsx
<NetFlow
  data={[
    { in: 42, out: 31 }, { in: 38, out: 35 }, { in: 45, out: 29 }, { in: 40, out: 44 },
    { in: 52, out: 38 }, { in: 48, out: 41 }, { in: 55, out: 36 }, { in: 50, out: 47 },
    { in: 58, out: 39 }, { in: 44, out: 52 }, { in: 60, out: 41 }, { in: 57, out: 43 },
  ]}
  positive="down"
/>
```

## Variants

```tsx
const months = [
  { in: 45, out: 29 },
  { in: 40, out: 44 },
  { in: 52, out: 38 },
  { in: 44, out: 52 },
  { in: 60, out: 41 },
  { in: 57, out: 43 },
];

<NetFlow data={months} mode="bars" />
<NetFlow data={months} positive="down" />
```

```tsx
<NetFlow
  data={[
    { in: 42000, out: 31000 },
    { in: 38000, out: 35000 },
  ]}
  locale="de-DE"
/>
```

The net label and accessible summary both follow `format`/`locale`: 38000 reads "38.000" under `de-DE` rather than the
English "38,000".

## Edge cases

```tsx
// an area through one point is a lie about continuity — NetFlow forces
// mode="bars" whenever there's only one period, regardless of the mode prop
<NetFlow data={[{ in: 40, out: 25 }]} title="This month" />
```

```tsx
// in/out are magnitudes; a negative reading is invalid data, not a
// direction — it renders as 0, never as flow the other way
<NetFlow data={[{ in: -5, out: -3 }]} title="Bad reading" />
```

A single period always renders as mirrored bars, never an area, since an area drawn through one point would imply
continuity the data doesn't have. `in`/`out` are magnitudes: a negative value is invalid input rather than a reversed
direction, so it is coerced to `0`. When every period's magnitudes are zero (all periods coerced or genuinely empty),
NetFlow draws only the zero baseline, with no areas, no bars, and no net line, and the accessible name says so plainly:
**"No flow across 1 period."**

## Four homes

**In a sentence**

```tsx
<p>
  Monthly cash flow{" "}
  <span className="mc-inline">
    <NetFlow data={months} summary={false} />
  </span>{" "}
  — net positive for the third month.
</p>
```

**In a table cell**

```tsx
<td>
  <NetFlow data={months} />
</td>
```

**In a KPI card**

```tsx
<div className="kpi">
  <span className="figure">+$42K</span>
  <span className="unit">this month</span>
  <NetFlow data={months} />
</div>
```

**In a tab header**

```tsx
<button className="tab">
  Operating <NetFlow data={months} />
</button>
```

## Accessibility

The accessible name pairs the net with its gross and counts the positive periods: **"Net +14 last period; in 57 vs out
43; net positive 4 of 6 periods."** The interactive entry steps the periods and announces inflow, outflow, and the
signed net together.

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, press `Escape`, or
press outside the chart. On touch, a tap pins and a drag scrubs.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `{ in; out }[]` | Periods, oldest first — inflow and outflow magnitudes (both ≥ 0). |
| `mode` | `"area" \| "bars"` | Mirrored areas (default) or discrete columns for few periods. |
| `net` | `boolean` | The net line (in − out). Default true. |
| `positive` | `"up" \| "down"` | Which direction is good — 'down' for debt-paydown contexts. |
| `label` | `"last" \| "none"` | Signed net in a right gutter. |
| `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).
