# Statements

> The largest gap in the market. No component library ships a <BalanceSheet />. This family is the reason Lopifi exists. Specs for 12 React components: StatementTable, StatementRow, ProfitAndLoss, BalanceSheet and 8 more.

Source: https://lopifi.com/docs/catalog/06-statements
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

# Statements

**The largest gap in the market.** No component library ships a `<BalanceSheet />`. This family is the reason Lopifi exists.

---

## 59. `StatementTable`

> The shared shell. P&L, balance sheet, and cash flow are all configurations of this.

### Structure
```
┌─ Toolbar: basis · period · comparison · currency · consolidation ─┐
├───────────────────────────────────────────────────────────────────┤
│ Account                 Sep 2026    Aug 2026    Change      %     │  ← sticky header
├───────────────────────────────────────────────────────────────────┤
│ Revenue                                                            │  section
│   Product revenue        482,100     441,200    +40,900   +9.3%   │  L2
│     Subscriptions        390,400     360,100    +30,300   +8.4%   │  L3
│     One-time              91,700      81,100    +10,600  +13.1%   │  L3
│   Services               118,400     102,800    +15,600  +15.2%   │  L2
│                         ─────────   ─────────  ─────────          │  ← single rule
│ Total revenue            600,500     544,000    +56,500  +10.4%   │  subtotal
│                                                                    │
│ …                                                                  │
│                         ═════════   ═════════  ═════════          │  ← double rule
│ Net income               142,880     118,400    +24,480  +20.7%   │  total
└───────────────────────────────────────────────────────────────────┘
```

### The craft

- **Indentation: 24px per level** (16px on phone). Levels 1–5. Deeper than 5 is a chart-of-accounts problem, not a UI problem.
- **Rule lines span the numeric columns only**, each period column independently, gutters unruled. This is the detail that makes it read as an accounting statement rather than a styled table.
- **Sticky account column** (left) and sticky header (top). Both, always. A P&L you scroll horizontally without the account names is unreadable.
- **Sticky total row** at the bottom for the grand total.
- **Expand/collapse is instant** — hundreds of times per close. The chevron rotates 140ms; the rows do not slide, grow, or stagger. This is the [Tier 0 concession](../motion/03-catalog.md).
- **Expansion state is in the URL**, so a shared link opens to the same view.
- **Zero values render as `—`.** Null renders as `n/a`. They are different facts.
- **Right-aligned, `tnum`, `case`, paren column reserved.** Negatives in parentheses, always — this is a statement.
- **Every column header states its period explicitly.** "Sep 2026", never "Current".
- **The statement header carries the full context**: entity, statement type, resolved period, basis (cash/accrual), presentation currency, and generation timestamp. Required for print, and required for the number to mean anything.

### Responsive
One period column at a time on phone, with a swipeable period selector and a fixed account column. Values crossfade at 140ms with no translation — translation would imply the labels moved too. Full spec in [responsive](../craft/04-responsive-and-input.md).

### Accessibility
Real table semantics, `<th scope="row">` on account names, `<caption>` with the resolved period, `data-level` for hierarchy (not `aria-level`, which is invalid outside a treegrid), `aria-expanded`/`aria-controls` on toggles, and subtotal/total status **in the row header text** — the rule line is invisible to a screen reader. Full spec in [accessibility](../craft/02-accessibility.md#financial-statement-semantics).

### Print
Repeating headers, `break-inside: avoid` on rows, `break-before: avoid` on totals so a total never orphans from its rule.

---

## 60. `StatementRow`
One line. Indent level, label, N period values, expand toggle, subtotal/total variant, drill-down affordance.

Server-safe (no `"use client"`) — a 400-row statement renders on the server. This is why `Money`, `Rule`, and `StatementRow` are all RSC-compatible; it's a real performance decision, not a purity one.

## 61. `ProfitAndLoss`
Revenue → COGS → Gross profit → Operating expenses → Operating income → Other → Net income.

- **Margin rows** (gross %, operating %, net %) rendered as a `Percent` level, with their period-over-period change in `points`, visually distinguished from the money rows — a percentage in a column of dollars needs to not look like dollars.
- **Comparison modes:** prior period, prior year, budget, forecast. Each with its own variance column.
- **Expense rows are `polarity="inverted"`.** An increase in COGS is not good news, and defaulting it to green is the bug this whole system exists to prevent.
- Optional per-line `WaterfallChart` drill-in showing what drove the change.

## 62. `BalanceSheet`
Assets → Liabilities → Equity, with the accounting identity checked and displayed.

- **The balance check is a first-class UI element**, not a footnote. `Assets 4,281,900 = Liabilities 1,840,200 + Equity 2,441,700 ✓` — and when it doesn't balance, that's a prominent error state with the difference stated, not a silently wrong statement.
- Current vs. non-current sub-grouping.
- **As-of date, not a period** — a balance sheet is a point in time and labeling it with a range is a category error the component prevents by taking a `Date`, not a range.
- Comparative columns: this date vs. prior period end vs. prior year end.

## 63. `CashFlowStatement`
Operating / Investing / Financing, with the reconciliation to the change in cash. Supports both direct and indirect methods. The **beginning-cash → ending-cash tie-out is displayed and asserted**, same as the balance sheet's identity.

## 64. `StatementToolbar`
Basis (cash / accrual) · period · comparison · presentation currency · consolidation scope · expand-all/collapse-all · export.

**The basis toggle is prominent and always visible.** A P&L on cash basis versus accrual basis are different statements, and a user who doesn't know which they're looking at is being misled. This is not a settings-menu item.

## 65. `PeriodPicker`
Fiscal-aware. Takes `fiscalYearStartMonth` and labels accordingly — `FY26 Q1` may start in July.

- Presets: this month, last month, QTD, YTD, this fiscal quarter, this fiscal year, trailing 12.
- **Every preset shows its resolved dates.** "Last quarter (1 Apr – 30 Jun 2026)".
- Custom range with a two-month calendar.
- **Closed/locked periods are visually marked** and warn on selection, because a "closed" period's numbers shouldn't be changing.

## 66. `VarianceCell`
Absolute change + percent change + significance. Significance is a threshold on both magnitude and materiality (a 200% swing on $12 isn't news), and the threshold is configurable because materiality is a business judgment.

Respects `polarity`. Division by zero → `n/a`, never `Infinity`.

## 67. `FluxAnalysis`
Period-over-period explanations attached to statement lines. Each variance can carry a written explanation with an author and timestamp — this is the actual month-end close workflow, and no library supports it.

Unexplained material variances are flagged. The flag list is the reviewer's worklist.

## 68. `DrilldownSheet`
Click a statement line → the GL entries behind it. Sheet on phone, side panel on desktop. **The entries sum to the line, and the sum is displayed** — that verification is the whole point of drilling down. Links onward to source documents.

## 69. `TrialBalance`
Every account with debit and credit columns and the proof that they're equal. The most boring component in the library and the one an accountant checks first.

## 70. `CloseChecklist`
Tasks, owners, dependencies, blockers, sign-off. Progress by section. Overdue items flagged with day counts. Sign-off is an `AlertDialog` with a hold-to-confirm — signing off a close is irreversible.
