CashFlowChart Composition
Money in and out per period, with the running balance over them. BalanceCurve shows that cash dips;
this shows why — which week's bills pull it under and which receipt brings it back. It is the shape
cash-forecast dashboards converge on: inflow bars up, outflow bars down, the balance as a line across both.
Usage
Below the line from Oct 12 — lowest −10M, 1 period(s) under.
| Period | In | Out | Balance |
|---|---|---|---|
| Sep 28 | Rp 12.000.000 | Rp 18.500.000 | Rp 33.500.000 |
| Oct 5 | Rp 0 | Rp 26.000.000 | Rp 7.500.000 |
| Oct 12 | Rp 4.000.000 | Rp 21.000.000 | -Rp 9.500.000 |
| Oct 19 | Rp 95.000.000 | Rp 14.000.000 | Rp 71.500.000 |
| Oct 26 | Rp 8.000.000 | Rp 19.000.000 | Rp 60.500.000 |
| Nov 2 | Rp 30.000.000 | Rp 12.000.000 | Rp 78.500.000 |
Press a week to list what is behind it.
Start from the real balance
opening is the balance before the first period — today's cash for a forecast, or the opening of a historical window. The line starts there and runs through
each period's close. Starting from zero draws a projection of change, which reads like a projection of
cash and is not one.
What it states
Above the plot, one sentence gives the two figures a decision needs: the first period below the threshold and the lowest balance. The period selector marks a dip, including one hidden inside a period that later closes above the threshold. A dot marks the lowest point on the plot; the sentence supplies its exact figure. Lightweight Charts draws the bars, line, threshold, grid and numeric axis. Hover a period on the plot to read its exact inflow, outflow and closing balance without interpreting the compact axis labels. If the period's intra-period low differs from its close, the detail shows that too.
Periods are the consumer's
The chart does not bucket. Pass days, weeks or months, each with its start day, inflow and outflow
(positive; a negative outflow is read as the same amount). A period bucketed from finer figures can dip and recover
inside itself — a week that is overdrawn on Wednesday and paid on Friday closes above zero. Pass its low
(the lowest balance within it) and the chart reads that against the threshold, marks its period and plots
the dip, so a mid-period shortfall is never hidden by the close. formatPeriod names a period on the
chart's axis and in the selector; by default it is its start day in the document's language. The
axis chooses which labels fit at the available width. An optional signed adjustment changes the running
balance without creating an inflow/outflow bar. It appears separately in exact details and the table;
use adjustmentLabel to name it. Never disguise a balance adjustment as a receipt or payment.
Interaction contract
Read-only unless onSelectPeriod is given. Then each period is a button named with its date and all three
exact figures, aria-pressed for selectedPeriod, so the consumer can list what is behind it beside the chart.
Keyboard focus on any period reveals the same exact-value detail as hover. Without an action callback,
periods remain focusable labelled images, not buttons that promise an unavailable action.
The detail follows the active period near the pointer, or its balance point during keyboard focus.
It flips and stays within the chart bounds near an edge rather than jumping to the opposite chart edge.
Pass periodControlsLabel to put the exact-value table in an initially closed native disclosure.
This leaves only the plot's date axis visible in a compact overview. Enter or Space on the summary
opens rows with the period, inflow, outflow, optional adjustment and closing balance. Numbers use
formatExact, not the abbreviated axis format. Read-only period labels are plain row headings;
when onSelectPeriod is provided they retain their selection buttons and keyboard detail.
Use periodLabel to translate the period column heading. Do not label a date-only selector as an
exact-amount table.
For a read-only overview where hover details are sufficient, omit periodControlsLabel and pass
compact. Period controls stay visually hidden until keyboard focus, while exact values remain
available in the screen-reader table. Do not add a second visible table merely to repeat the plot.
Accessibility
A visually hidden table gives every period's in, out and balance by default. With periodControlsLabel,
the same table is visible when the disclosure is opened; there is no duplicate hidden table or date
selector. The canvas is aria-hidden because the table is the exact accessible rendering. Under
forced-colors: active the canvas is replaced by an always-visible table, even with a disclosure label.
Pass formatExact when format abbreviates the axis; the library has no currency
assumption. The chart has no entry animation, including under reduced motion.
Do
Use it for a forecast where the reader has to see which flows cause a dip.
Don't
Use it for a plain balance with no flows to explain — that is BalanceCurve.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
| label | string | — | Visible title and accessible name. Required. |
| opening | number | — | The balance before the first period. Required. |
| periods | CashFlowPeriod[] | — | `{ id, start, inflow, outflow, adjustment?, low? }` in order; adjustments affect balance, not flow bars; `low` is the lowest balance within the period. |
| format | (value: number) => string | — | How a value is written. The product owns this. |
| formatExact | (value: number) => string | format | Full-precision values for hover, focused period buttons and the accessible table. |
| formatPeriod | (start: string) => string | — | How a period is named. Defaults to its start day. |
| threshold | { value: number; label?: string } | { value: 0 } | The line the balance is read against. |
| onSelectPeriod | (id: string) => void | — | Makes each period a button. |
| selectedPeriod | string | — | The period whose detail the consumer is showing. |
| height | number | 240 | Plot height in pixels. |
| inflowLabel / outflowLabel / balanceLabel | string | 'In' / 'Out' / 'Balance' | Legend, table and button words. |
| lowestLabel | string | 'Low' | Hover label when the lowest intra-period balance differs from the closing balance. |
| adjustmentLabel | string | 'Adjustment' | Exact detail and table label for non-flow balance changes. |
| periodLabel | string | 'Period' | Heading for the exact table's period column. |
| belowLabel | (from, lowest, periods) => string | — | The sentence when the balance goes below the line. |
| clearLabel | (lowest) => string | — | The sentence when it never does. |
| tableLabel | string | 'Cash flow by period' | Caption of the exact-value table. |
| periodControlsLabel | string | — | Optional label for an initially collapsed visible exact-value table. Omit to keep expanded period controls and a screen-reader table. |
| compact | boolean | false | Visually hide undisclosed period controls until keyboard focus; keep the exact screen-reader table and forced-colors fallback. |
| emptyLabel | string | 'Nothing to project yet.' | Shown when there are no periods. |
| locale | string | — | Language for default period names; the document's `lang` when omitted. |
| className | string | — | Added to the root element. |
Tokens
--cb-tone-success fills inflows, --cb-tone-danger fills outflows and marks a period below the
threshold, --cb-tone-brand draws the balance and low point, --cb-border draws the grid and selector
separator, --cb-fg-muted the axis text, --cb-focus-width the focus ring, and the existing
--cb-radius-*, --cb-space-*, and --cb-text-* Tokens size the component.