Making invoice PDFs in the browser: page breaks, money maths and one trade-off
I run a free invoice generator, PDF Bill Builder . The PDF is built entirely in the visitor's browser, so nothing is uploaded unless they sign in to save a document. Three problems took longer than I expected. Here is how each one ended up. 1. Render the preview, then slice it The design lives in one React component: the live preview. To keep the download identical to the preview, I capture that…
Creating invoices in a web browser using PDF Bill Builder presents three challenges that took longer to solve than anticipated. The first challenge involves rendering a preview of the invoice and then slicing it into a PDF format. To ensure the download matches the preview exactly, the design lives in a single React component displaying the live preview.
Capturing the same DOM with html2canvas-pro and placing the image into a PDF with jsPDF requires a conversion from pixels to millimetres. This conversion relies on a fixed width for A4 (794px) and US Letter (816px) page sizes.
The second challenge is ensuring that rows in a lengthy invoice are never cut in half when the canvas is sliced into pages. To address this, the preview marks which elements may not be split, such as table rows. The slicer collects the top and bottom y-position of every marked element, relative to the captured root. For each page, the largest candidate that is no further than one page height from the start and no earlier than 35% of the page is selected. If a single block is taller than a page, a hard cut is used instead.
The third challenge revolves around handling money calculations. Invoices may involve tax additions, percentage or fixed discounts, and 18 different currencies. All these factors create multiple edge cases. To tackle this, the calculations are moved into a single pure function to ensure the preview and PDF read the same numbers and agree with each other.
Two key points are rounding every line to two decimal places before summing them, which matches what a printed invoice shows, and using a custom round2 function that rounds half up with a small epsilon. This function takes care of financial precision issues such as 1.005 rounding to 1.01 instead of 1.00. Tax included is shown as informational only, while tax on top adds to the total.
The function is tested with unit tests, providing the cheapest insurance against sending clients an invoice with an incorrect total.
In summary, creating invoice PDFs in the browser involves three main hurdles: rendering a precise preview and converting it to a PDF while maintaining visual fidelity, preventing table rows from being cut in half during slicing, and handling complex money calculations with taxes and discounts accurately. By treating the preview as the single source of truth, marking break-safe blocks, and keeping money math pure and thoroughly tested, these challenges can be overcome effectively.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.