Skip to content

How to align numbers in a table

Right-aligned is not aligned. Getting a column of money to read as a column is four settings and one rule line, and it is the difference between a finance product and an admin template with a dollar sign.


1. Turn on tabular figures

By default most typefaces set numerals proportionally — a 1 is narrower than a 0. That is correct for prose and wrong for a column, where it means the digits in row four do not sit above the digits in row five.

.numeric {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

Inter has tnum. So does almost every UI typeface worth using. Switch it on for every numeral a reader might compare with another numeral — which in a finance interface is all of them, including dates, reference numbers and quantities.

2. Turn on case-shifted parentheses

case (cv## in some fonts) shifts brackets, dashes and other punctuation up to sit optically centred against lining figures rather than lowercase text. Without it, (1,234.00) has parentheses that hang slightly low against the digits.

font-feature-settings: "tnum" 1, "case" 1;

Both features, always, on anything numeric. This pairing is the single cheapest credibility gain in a financial interface.

3. Align on the decimal point, not the right edge

Right-alignment gets you most of the way only because fixed decimal places make the two equivalent. Which is the actual rule:

Fixed decimals throughout. $1,200.00, never $1,200.

Intl does this by default. The bug is introduced by someone trimming trailing zeros to "clean up" the column. Once one value in a column has two decimals and another has none, right-alignment stops aligning anything.

Where a column genuinely mixes scales — a rate at three decimals beside an amount at two — align on the decimal separator explicitly with a grid, rather than hoping padding holds.

4. Reserve the sign column

A column mixing 1,234.00 and (1,234.00) loses its alignment to the closing paren. Reserve the slot on both sides. The three ways to do it are ranked in negative numbers in a financial table.

5. Rule lines carry the arithmetic

A single rule above a subtotal, a double rule under a total. This is four centuries of convention and two CSS declarations:

<Rule variant="subtotal" />   // border-top: 1px solid
<Rule variant="total" />      // border-bottom: 3px double

The rule spans the numeric column only, not the label column. That is what makes it read as accounting rather than as a divider. In a multi-period statement it spans each period column independently, with the gutters left unruled. Never combine a rule with a background fill on the same row — pick one, and it should be the rule.

6. Do not stripe the rows

Zebra striping is what you reach for when the numbers are not aligned. Fix the alignment and the stripes become noise: the tabular figures do the work, and a hairline row separator handles the rest at any density.

7. Never animate a value the reader might trust

A number counting up from zero is unreadable for the duration of the animation, and a reader who glances mid-tween takes away a figure that was never true. Crossfade a changed value if you must signal the change; never interpolate it.


Where this is implemented

  • Rule — ten lines of code, the highest credibility-per-byte component here
  • StatementTable — hierarchy, period columns and rules together
  • LedgerTable — debit and credit as two aligned columns
  • TransactionTable — virtualised, and still aligned at 240 rows
  • Tables, running — with a density toggle, which is the real test of an alignment claim
  • Typography — the type system these features live in
  • Numerics — rule lines, in full

Told when this spec changes

The docs are the contract the components are built against. When one changes, the component changes with it — and the copy in your repo does not. One email when that happens.

One address, no list rental, unsubscribe in one click.

Works in your QuickBooks Online or Xero file

Get your books closed every month

Lopifi is building AI bookkeeping that keeps your books closed on US GAAP as transactions happen, with a CPA review every quarter, for $200 a month. We’re not open yet.

$200/month when we open. No card now.