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.
- Expansion state is in the URL, so a shared link opens to the same view.
- Zero values render as
—. Null renders asn/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.
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.
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
Percentlevel, with their period-over-period change inpoints, 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
WaterfallChartdrill-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.