StatementTable
The IBCS table with measure rows and integrated waterfalls (templates T03/T04) - a P&L or balance sheet with embedded variance bars and pins.
A financial statement rendered as one integrated view: the label column, an embedded waterfall lane for the actual scenario, and right-hand variance panels against each comparison base. Deviation and structure are read in a single pass, without leaving the table.
When to use
An income statement, a balance sheet, or any build-up of figures to subtotals - lines that add, subtract and resolve into results. For a cross-entity comparison (revenue by region, headcount by team) where rows do not build up to a total, use DataTable instead.
Example
| PY | AC | ΔPY | ΔPY% | |
|---|---|---|---|---|
| 16.1M | ||||
| 9.5M | ||||
| = | 25.6M | |||
| − | 3.1M | |||
| − | 5.3M | |||
| = | 17.2M | |||
| − | 3.5M | |||
| − | 4.3M | |||
| − | 1.4M | |||
| = | 8M | |||
| 276K | ||||
| = | 8.3M | |||
| − | 195K | |||
| = | 8.1M |
import { StatementTable } from "ibcs-react";
<StatementTable
lines={statement}
varianceColumns={[
{ base: "PY", mode: "abs", mark: "bar" },
{ base: "PY", mode: "pct", mark: "pin" },
]}
mark="bar"
format={{ compact: true, decimals: 1 }}
/>;Pin mark and relative variance
Draw the waterfall lane as pins and add a percent (ΔPY%) panel - pins keep small bases honest against the absolute bars.
| PY | AC | ΔPY | ΔPY% | |
|---|---|---|---|---|
| 16.1M | ||||
| 9.5M | ||||
| = | 25.6M | |||
| − | 3.1M | |||
| − | 5.3M | |||
| = | 17.2M | |||
| − | 3.5M | |||
| − | 4.3M | |||
| − | 1.4M | |||
| = | 8M | |||
| 276K | ||||
| = | 8.3M | |||
| − | 195K | |||
| = | 8.1M |
<StatementTable
lines={statement}
mark="pin"
varianceColumns={[
{ base: "PY", mode: "abs", mark: "bar" },
{ base: "PY", mode: "pct", mark: "pin" },
]}
format={{ compact: true, decimals: 1 }}
/>Stock mode - a balance sheet
The same component renders point-in-time levels instead of a flow waterfall:
each line is an absolute bar, with no running total. Liability lines carry
higherIsBetter: false, so a rise in debt reads as unfavorable. Groups with
children collapse and expand.
| PY | AC | ΔPY | ΔPY% | |
|---|---|---|---|---|
| 14.8M | ||||
| 6.5M | ||||
| 4.9M | ||||
| 3.4M | ||||
| 19.2M | ||||
| 11.2M | ||||
| 6.3M | ||||
| 1.7M | ||||
| = | 34M | |||
| 17.3M | ||||
| 3.6M | ||||
| 3M | ||||
| 9.5M | ||||
| 1.2M | ||||
| 16.7M | ||||
| 5M | ||||
| 11.7M | ||||
| = | 34M |
<StatementTable
lines={balanceSheet} // ending balances, not period movements
mode="stock" // absolute levels, not a waterfall
format={{ compact: true, decimals: 1 }}
/>Collapsed groups: controlled or uncontrolled
Grouped statements track a collapsed set of group ids. Both modes are supported, and mixing them is the usual mistake:
- Uncontrolled - pass
defaultCollapsed(a seed applied on mount, which overrides each line's owndefaultCollapsedflag) and let the table own the state.onCollapsedChangestill fires, as a plain observer. - Controlled - pass
collapsed(aReadonlySet<string>or a string array). The table then renders exactly that set and never mutates it; every toggle, and the Expand all / Collapse all buttons, report the next ids throughonCollapsedChangefor you to apply - useful for URL sync, persistence, or keeping two tables in step.
const [collapsed, setCollapsed] = useState<string[]>(["noncurrent-assets"]);
<StatementTable
lines={balanceSheet}
mode="stock"
expandControls
collapsed={collapsed}
onCollapsedChange={setCollapsed}
/>;Set maxHeight for long consolidations: the body scrolls under a sticky
header and row virtualization turns on by default (virtualize).
Props
Prop
Type