PDFPipe

Getting paid / Prepayment and balance

Showing a deposit already paid and the balance still due

A block that subtracts what has already been received from the invoice total and states the remaining amount, which is the only figure the payer should act on.

Why this block is harder than it looks

Two amounts on one document both look like the amount owed, and only one of them is. Every failure here is a payer sending the wrong figure: the full total when a deposit was already paid, or the balance when the deposit had not in fact cleared. The layout has to make one of the two figures unmistakably the operative one, which means it cannot simply be the last row of the totals block in the same weight as the rest. The second difficulty is that the prepayment needs identifying, by date and reference, or the payer cannot reconcile it against their own records.

The decisions that make it work

Reasons rather than a description of the code. Each of these is a choice that has a wrong answer, and the wrong answer is usually the default.

  • Give the balance its own visual level: heavier, larger, and separated by a rule from the arithmetic above it. There should be no ambiguity about which figure to pay.
  • Show the subtraction rather than only the result. Total, less deposit, balance, in that order, so the payer can see where the number came from.
  • Identify the prepayment with its date and reference on the same line, in smaller type. A deposit line with no reference cannot be reconciled.
  • Print the balance even when it is zero, with a label saying nothing is due, rather than omitting the block. An absent block reads as an oversight.
  • Never repeat the gross total anywhere below the balance. The last large number on the page is the one people pay.
  • Keep the whole thing in one break-inside: avoid container, because a balance separated from the deposit it depends on is the worst possible split.

The fragment

Markup and the CSS it needs, and nothing else. It expects a document that already has a page rule and a base stylesheet, so paste it into one rather than opening it on its own.

html
<section class="balance-due">
  <div class="row"><span>Invoice total</span><span class="v">5,016.00</span></div>
  <div class="row less">
    <span>Less deposit received
      <span class="ref">14 Feb 2026, ref DEP-0091</span></span>
    <span class="v">&#8722;1,500.00</span>
  </div>
  <div class="row final"><span>Balance due</span><span class="v">3,516.00</span></div>
</section>

<style>
  .balance-due {
    break-inside: avoid;
    width: 48%;
    margin-left: auto;
  }
  .balance-due .row {
    display: flex;
    justify-content: space-between;
    gap: 10pt;
    padding: 3pt 0;
  }
  .balance-due .ref { display: block; font-size: 7.5pt; color: #666; }
  .balance-due .final {
    border-top: 1.5pt solid currentColor;
    margin-top: 5pt;
    padding-top: 6pt;
    font-size: 13pt;               /* the operative figure, unmistakably */
    font-weight: 700;
  }
  .balance-due .v {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
</style>

What breaks when it is built the obvious way

Setting the balance in the same size and weight as the invoice total. Both are then candidates for the amount owed, the payer picks one, and half of them pick the one that was already paid. Size is doing real work here and it is not decoration.

How to prove it survived pagination

Show the rendered page to somebody for three seconds and ask what they would pay. If the answer is not the balance, the hierarchy is not strong enough. Then render the zero-balance case and confirm it says nothing is due rather than showing an empty block.

Where it sits in a finished document

This page is one block. The document it belongs to has a page rule, a base stylesheet, a header and everything else around it, and repeating all of that here would make thirty pages that say the same thing. The proforma invoice template is a complete file with this block already in it, so take that and change the fragment rather than assembling one from parts. The property doing most of the work here is covered on its own page, with the support caveats that belong there rather than here.

Frequently asked

Will this fragment work on its own?

Not as a whole document. It has no page rule, no margins and no base type, because those belong to the document rather than to the block, and duplicating them in every fragment would mean thirty copies to keep in step. Paste it into a template that already has them.

Why does it look right in a browser and wrong in the PDF?

Because a browser window is one continuous surface and a document is a stack of fixed rectangles. Nothing in a scrolling view exercises a page boundary, so every break rule in the fragment is inert until the content is paginated. Render the real thing with enough content to cross two or three boundaries, then look.

Do I need a special option on the render request for this?

No. Everything on this page is CSS and markup, which is your side of the boundary. What the render has to give you is a real page size with real margins, and after that the layout is decided by the stylesheet.

Other parts of a document

The blocks that sit next to this one, and one from the next group along so you are not sealed inside a single kind of problem.

Paste the fragment into the playground inside a page rule and see what it does at a real page size. That is the only way any of this gets confirmed.