PDFPipe

Formatting and locale / Numbers and money

Negative amounts in accounting format, and the missing minus

A negative figure written with a leading minus, with parentheses, or with a trailing sign, where the conventions differ and one of them is easy to miss entirely.

The defect

The accounting convention writes a negative in parentheses rather than with a sign, and a reader who does not know that reads a bracketed figure as a positive with a note attached. A leading minus has the opposite problem: at small sizes, next to a digit, a minus sign is easy to overlook, and a hyphen used in its place is easier still. Either way the failure is the same and it is the worst one available in a financial document: a figure read with the wrong sign, which is an error of twice the amount. The document also has to survive the sign changing width, which is what makes a column of mixed signs go ragged.

What it does to the document

Parentheses are wider than a minus sign, so a column mixing the two conventions, or mixing bracketed negatives with unbracketed positives, has two different effective widths. Reserving the space on every row, positive or negative, is what keeps the right edge straight.

The decisions

Reasons rather than a description of the code. Formatting rules are data that changes, so most of these are about taking the rule from a maintained source rather than encoding today's answer.

  • Pick one convention for the whole document and state it if it is the accounting one. Parentheses meaning negative is a convention, not a universal.
  • Use a real minus sign rather than a hyphen. A hyphen is narrower, sits at a different height, and is what a reader mistakes for a stray mark.
  • Give the sign its own fixed-width slot to the left of the digits so a negative row does not shift relative to a positive one.
  • Never rely on colour alone. Red for negative is invisible in monochrome, which is how most documents are read.
  • Be consistent about what a negative means in context. On a credit note the whole document is a reversal, so printing every figure negative as well is a double negative the reader has to resolve.
  • Format with a library so the convention comes from the locale rather than from a template written by whoever was there first.

In code

The formatting happens before the markup exists, so this is mostly code rather than CSS. The wrong version is kept in a comment where the wrong version is the thing people write.

js
const amount = -620;

// The locale decides the convention. Accounting sign display asks for
// the parenthesis form where the locale uses it.
new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencySign: "accounting",
}).format(amount);

// A real minus sign, not a hyphen: U+2212.
const withMinus = "\u2212620.00";

/* Fixed-width sign slot, so a negative row does not shift the digits:
   .v      { font-variant-numeric: tabular-nums; white-space: nowrap; }
   .v .sign { display: inline-block; width: 6pt; }                      */

What people do instead

Marking negatives with red text and nothing else. It is clear on screen, invisible on a monochrome print and on a photocopy, and the figure then reads as a positive. This is the one formatting decision in the cluster that changes an amount rather than merely making it harder to read.

How to find out rather than assume

Print the document in greyscale and read a page containing both signs. Every negative should still be identifiable. Then look along the right edge of the column: if the negative rows are offset from the positive ones, the sign is inside the aligned block rather than in its own slot.

Where the API sits in this

Nowhere, and that is worth saying plainly. This API renders HTML to PDF. By the time markup reaches it, every value in it is already a string that somebody's code produced, so there is no locale option on the render because there would be nothing for one to do. What the render controls is the page: the size, the margins, and whether the formatted value still fits the column it landed in. That is why each of these pages has a paragraph about the layout consequence, because that is the half a document adds to the general problem.

Frequently asked

Should the document use the sender's conventions or the reader's?

That is a decision rather than a fact, and the only wrong answer is not making it. The issuer's conventions are defensible for a document that is a record of what the issuer did. The recipient's are defensible for a document meant to be acted on. What fails is a document that mixes them, because a reader who sees two conventions on one page cannot tell which one any given figure is in.

Is it enough to set the document language?

No. A language attribute helps with hyphenation, with the assistive technology reading order and with anything that needs to know what language the text is in, and it changes none of the values. A date formatted as 03/04/2026 is exactly as ambiguous in a document declared as English as in one declared as anything else. The values are formatted upstream.

Why does this belong in a document reference rather than a general one?

Because a document cannot be re-rendered by its reader. On a screen a wrong format is annoying and a user can often change a setting. On paper the format is final, the layout was tuned to the string lengths of one language, and a value that grew by a few characters can push a table onto another page. The formatting problem and the pagination problem are the same problem here.

Related formatting topics

The defects that travel together, then the rest of the same group.

Values are formatted by your code before they reach the markup, so every fix on this page is upstream of the render. What the render decides is whether the result still fits.