# How to align numbers in a table

> Right-aligned is not aligned. Tabular figures, case-shifted parentheses, decimal alignment, a reserved sign column and rules that carry the arithmetic.

Source: https://lopifi.com/docs/guides/03-align-numbers-in-a-table
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

# How to align numbers in a table

<!-- description: Right-aligned is not aligned. Tabular figures, case-shifted parentheses, decimal alignment, a reserved sign column and rules that carry the arithmetic. -->

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.

```css
.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.

```css
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](02-negative-numbers-in-financial-tables.md#the-alignment-problem).

## 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:

```tsx
<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`](/components/rule) — ten lines of code, the highest credibility-per-byte component here
- [`StatementTable`](/components/statement-table) — hierarchy, period columns and rules together
- [`LedgerTable`](/components/ledger-table) — debit and credit as two aligned columns
- [`TransactionTable`](/components/transaction-table) — virtualised, and still aligned at 240 rows
- [Tables, running](/showcase/tables) — with a density toggle, which is the real test of an alignment claim
- [Typography](../foundations/05-typography.md) — the type system these features live in
- [Numerics](../foundations/06-numerics.md#rule-lines) — rule lines, in full
