Thermal receipt template: 58 mm and 80 mm sizes, margins and print settings
Almost every "my receipt prints wrong" problem comes down to one thing: the page is not the width of the paper. Thermal paper does not have a page size in the way A4 does, so the browser guesses, and it guesses A4. Here are the real numbers for both common rolls and the setup that makes a receipt come out at 1:1.
The two roll widths that matter
Receipt printers come in exactly two sizes worth caring about. The roll width is the paper. The printable width is narrower, because the print head does not reach the edges and the paper wanders slightly as it feeds.
| Roll | Printable | Dots at 203 dpi | Font A | Font B |
|---|---|---|---|---|
| 58 mm | 48 mm | 384 | 32 chars | 42 chars |
| 80 mm | 72 mm | 576 | 48 chars | 64 chars |
203 dpi is 8 dots per millimetre, which is the resolution of essentially every receipt printer sold. 48 mm × 8 = 384 dots. 72 mm × 8 = 576. Font A is a 12 × 24 dot cell, so 384 ÷ 12 = 32 characters per line. Font B is 9 × 17, so you get 42. That is where the famous 32 and 48 column limits come from: they are not a convention, they are arithmetic.
Older or cheaper 80 mm printers sometimes have a 512 dot head instead of 576, giving 42 columns in Font A. If your text wraps a character or two early, that is why. Print a line of 48 hashes and count what survives.
Why your receipt prints cut off
When you print an HTML page, the browser lays it out for a page size. If nothing tells it otherwise that page is A4 or Letter, 210 mm wide. Your 58 mm printer receives a 210 mm wide page and does one of two things, both wrong: it clips everything past 48 mm, or the driver scales the whole page down to fit and you get 3 pt text you cannot read.
The fix is one CSS rule. Tell the print engine the page is the width of the paper:
@page {
size: 58mm auto; /* or 80mm auto */
margin: 0;
}
.receipt {
width: 48mm; /* printable width, not roll width */
margin: 0 auto;
padding: 2mm;
font-family: "Courier New", monospace;
font-size: 9pt;
}
auto for the height is the important half. A receipt is not a page, it is a continuous
strip, and the length depends on how many lines you have. Fixing the height to 297 mm makes the
printer feed a wasteful blank tail after every short receipt.
The three print dialog settings that break it anyway
- Scale. Set it to 100%, never "Fit to page". Fit to page will happily shrink your 48 mm layout to 40 mm and your barcode will stop scanning.
- Margins. Set them to None. Browser default margins are around 10 mm each side, which on a 58 mm roll leaves you 28 mm of usable width.
- Headers and footers. Turn them off, or every receipt gets the page URL and the date printed across it.
What actually belongs on a receipt
Layout aside, a receipt that a customer or an accountant will accept has a predictable set of blocks. In order, top to bottom:
- Header: business name, address, tax or VAT number, phone.
- Document line: receipt number, date, time, till and operator.
- Items: description, quantity, unit price, line total. Longer names wrap to a second line rather than being truncated.
- Totals: subtotal, discounts, service or delivery, tax, then the grand total in the largest type on the receipt.
- Tax summary: one row per rate, showing net, tax and gross. Required in most of Europe once you are VAT registered.
- Payment: method, amount tendered, change, card brand and last four digits.
- Footer: thank you line, return policy, and a barcode or QR code carrying the receipt number.
Typography on a 32 column strip
Thermal receipts are set in a monospace font for one reason: columns. If the price column does not line up, the receipt looks broken even when the arithmetic is perfect. Use a monospace family, right align every number, and pad with spaces rather than tabs.
Keep the font size between 8 and 10 pt. Below 8 pt the thermal dots merge and the print smudges after a few weeks in a wallet. Above 10 pt you lose columns and item names start wrapping constantly.
Resist decoration. Thermal printing is one colour, and grey backgrounds come out as a muddy grid of dots. Separate sections with a row of dashes, not with boxes and shading.
Barcodes and QR codes on a narrow roll
A Code 128 barcode needs quiet zones, at least 10 times the narrow bar width of blank space on each side. On a 58 mm roll that means keeping the bars under about 40 mm wide. If the scanner refuses to read your barcode, the quiet zone is the first suspect, ahead of the print quality.
QR codes are more forgiving, but keep the module size at 3 dots or more. A version 4 QR at 2 dots per module is 66 dots wide, which looks fine on screen and reads as a smudge on paper.
Generate both widths right now
Free 58 mm and 80 mm receipt generator
Both widths are built in with the page size, margins and column count already correct. Fill in the lines, hit print, and it comes out at 1:1 on the roll. There is also a plain text export in true 32 or 48 column width if you are driving the printer over ESC/POS instead.
Open the receipt generatorWritten by Oliver Žaigla, who builds software for a living. The generator is free and has no account, no watermark and no upload. If it saved you an afternoon, buy me a coffee. If you need one of these built properly, write to oliver@zaigla.com.