# Financial Tables

> Table design for financial data - hierarchical P&L and balance sheet layouts with roll-ups, column ordering, conditional formatting that earns its ink, in-table sparklines and bars, totals discipline, sticky headers, and print behaviour. The table is often the real deliverable, not the chart. Trigger on "table", "P&L layout", "financial statement table", "data table", "sparkline in table", "conditional formatting", "totals row", "sticky header", "make this table readable".

- Skill: `lukehle/financial-tables` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lukehle/financial-tables`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lukehle/financial-tables/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Lukehle (https://skillmd.com/u/lukehle)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lukehle/financial-tables

---


# Financial tables

Finance audiences read tables. They will read a well-set table faster than any chart, because they
know the shape of a P&L and they want the exact numbers.

**Treat the table as a primary deliverable, not as a fallback.** Most dashboards would be improved by
one strong table and one chart, instead of six weak charts.

---

## Non-negotiables

Three lines of CSS and one rule fix most unreadable tables:

```css
table { border-collapse: collapse; width: 100%; }
td, th { font-variant-numeric: tabular-nums; }   /* digits stack */
.num { text-align: right; }                      /* numbers right, labels left */
```

Plus: **consistent decimal places within a column.** Ragged precision is the single most common
reason a numeric column will not scan.

---

## Hierarchical statements

A P&L is a tree. Encode the hierarchy with **indentation and weight**, never with borders.

```
Revenue                                    4,820,115
  Subscription                             4,412,880
  Services                                   407,235
                                          ──────────
Cost of revenue                           (1,156,828)
  Hosting                                   (612,400)
  Support                                   (544,428)
                                          ──────────
Gross profit                               3,663,287        ← bold, rule above
  Gross margin %                                76.0%        ← muted, derived
```

- **Indent children** (12-16px per level). Two levels is usually enough; three is the practical
  maximum.
- **Subtotals in weight 600 with a rule above.** The rule signals summation.
- **Grand totals get a double rule** — the accounting convention, and readers look for it.
- **Derived metrics (margin %) sit muted beneath their line**, so they read as commentary rather
  than as another line item.
- **Negatives in parentheses** in tables, per accounting convention (`data-typography`).
- **Every subtotal must equal the sum of its children.** If it does not because of exclusions or
  rounding, add a visible reconciling line rather than letting the reader find the gap.

---

## Column order

Left to right, in the order the eye needs:

```
Line item │ Actual │ Prior │ Δ │ Δ% │ Plan │ vs Plan │ vs Plan %
```

- **Label column first**, then the primary figure.
- **Comparison immediately after the value it compares to** — not at the far right where the eye must
  travel.
- **Absolute delta before percentage delta.** The absolute is the more important number and readers
  hit it first.
- Cap at about eight columns before splitting into two tables or moving detail behind a drill-down.
- Right-align the header over a numeric column; a left-aligned header over right-aligned numbers
  looks broken.

---

## Conditional formatting that earns its ink

The failure mode is a table lit up like a Christmas tree, where nothing stands out because
everything does.

**Rules:**
- **Format only the column that needs attention** — usually variance, not every numeric column.
- **Threshold-based, not gradient.** Highlight what breaches materiality; do not shade all 200 rows
  by magnitude.
- **Background tint, not coloured text.** Coloured text at 13px fails contrast; a light wash with
  dark text passes.
- **Never colour alone.** Pair with a glyph or the sign (`artifact-accessibility`).
- Aim for **under ~10% of cells** carrying any emphasis. Above that, raise the threshold.

```css
.variance.breach     { background: var(--negative-wash); }
.variance.favourable { background: var(--positive-wash); }
```

---

## In-table visuals

A small visual in a table row is often better than a separate chart.

**Sparklines** — 12-month trend in the width of a column.
- **Must carry a reference point**: a baseline, a min/max dot, or an end value. A bare line with no
  scale reads as "trend" but cannot be measured, and a flat line at high volatility looks identical
  to a flat line at low volatility.
- Consistent y-scale across rows if rows are comparable; if not, say so.
- Mark them `aria-hidden="true"` and keep the value in an adjacent cell.

**In-cell bars** — magnitude comparison down a column.
- Bar plus the number, not bar alone.
- Shared scale down the column.
- Excellent for a ranked variance column; the eye sorts instantly.

**Delta indicators** — `▲ 12.4%` with the glyph carrying direction and colour reinforcing.

---

## Long tables

- **Sticky header** so column meaning survives scrolling:
  ```css
  thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }
  ```
  Give it an explicit background or rows will show through.
- **Sticky first column** for wide tables, same technique with `left: 0`.
- **Zebra striping only above ~15 rows**, and very subtle. Below that it is noise.
- **Row hover highlight** helps track across a wide row — cheap and effective.
- Above ~500 rows, paginate or virtualize (`artifact-data-loading`).
- **Group with subheader rows**, not with alternating background blocks.

---

## Totals

- **Totals at the bottom** for a statement (the reading order builds to them); **at the top** for a
  dashboard summary where the total is the headline.
- **A totals row must be visually distinct** — weight, a rule, and a slightly different background.
- **Sticky totals** on a long scrolling table are a real quality-of-life win.
- **If the total does not equal the visible rows** because of filtering, say so explicitly:
  *"Total reflects all 14,882 rows; 200 shown."* Otherwise the reader will try to add up the column
  and conclude something is broken.

---

## Print and accessibility

```css
@media print {
  thead { display: table-header-group; }   /* repeat headers on each page */
  tr    { break-inside: avoid; }
}
```

- Real `<table>` markup with `<th scope="col">` / `<th scope="row">` and a `<caption>`. A grid of
  `<div>`s cannot be navigated by a screen reader — it cannot announce "row 4, Professional fees,
  $178K".
- The caption states what the table is, including period and basis.
- Do not rely on colour alone for any status column.

---

## When a table beats a chart

- Values will be read off precisely
- More than about 15 categories
- Multiple measures per row that must be compared
- The audience knows the standard layout (P&L, balance sheet, cash flow) — deviating from a familiar
  shape costs more than a chart gains
- Precision matters more than pattern

The strongest reporting page is usually **one chart that carries the finding, and one table that
carries the detail.**

---

## Related skills

- `data-typography` — tabular figures, alignment, precision
- `artifact-data-loading` — pagination and virtualization
- `artifact-accessibility` — table semantics
- `visual-hierarchy` — where the table sits
- `chart-annotation` — captions and footnotes

