After an e-commerce transaction completes, the system usually produces an order confirmation that the customer uses to verify products, shipping information, and payment amounts, and that the warehouse uses for picking and the support team uses for after-sales reconciliation. Traditional order confirmations come from backend templates that are slow to update and prone to Chinese font issues, while printing the web page drags navigation bars and recommendations into the output. dompdf.js generates order confirmations in one step on the frontend: order data is assembled into HTML, rendered to vector PDF, and downloaded or printed with a clean, uniform layout. This article covers the complete e-commerce order confirmation PDF workflow, including template design, the payment summary area, multi-product pagination, batch export, and common pitfalls, and is suitable for e-commerce platforms, ERP systems, and independent storefronts. We will also discuss internationalization for cross-border stores, merchant-customizable templates, and the data hygiene rules that keep order documents accurate. Whether you run a marketplace, an ERP, or a small storefront, the frontend approach removes an entire class of server-side problems and gives you print-ready documents the moment an order is placed.
An order confirmation plays multiple roles in e-commerce. For the customer it is proof of purchase that verifies products, prices, and delivery details; for the warehouse it is the picking instruction used to prepare and ship goods; for finance and support teams it is the reconciliation record that anchors refunds, exchanges, and complaints.
A complete order confirmation contains: order number and order time; receiver name, phone, and address; line items with name, specification, unit price, quantity, and subtotal; the payment summary with goods total, shipping, discount, and amount paid; and payment method plus shipping information. No element is optional.
Order volumes are enormous, with peak days reaching tens of thousands of orders. Backend PDF generation adds load to the server and threatens the stability of core transaction APIs. Frontend generation spreads the rendering load across every user's browser, leaving the server untouched no matter how high concurrency goes.
Internationalization is a growing requirement. Cross-border stores need order confirmations in English or bilingual format, with product names, specifications, and addresses translated. A frontend template can pull strings from a language dictionary keyed to the store's locale, and address formatting should follow the local convention, such as the smallest-to-largest ordering used in English addresses, so parcels actually reach the customer.
Order confirmations also support operations beyond the customer experience. Finance uses them to reconcile payments, the support team references them during returns and complaints, and marketing can attach them to post-purchase emails. Making the template data-driven means every department reads the same canonical document, which removes a surprising amount of internal friction.
Order confirmations also matter for dispute resolution. When a customer claims an item was never ordered, the confirmation is the neutral record both sides consult. Including the exact timestamp, the payment reference, and the item-level prices makes that record far more useful than a screenshot of a web page could ever be.
For B2B orders, the confirmation doubles as a purchase record for the buyer's own procurement process. Including the buyer's PO number, the salesperson's contact, and delivery terms turns the document into a small contract artifact that both procurement and accounts payable can file.
Order confirmations have a fixed structure but many fields, and HTML tables describe them perfectly. dompdf.js renders the DOM to vector PDF, so the order template and the web template share the same source. Development and debugging are efficient, and product details, amounts, and shipping information render precisely.
E-commerce places extreme demands on Chinese support: product names, shipping addresses, and notes can contain rare characters and special symbols. dompdf.js bundles Source Han Sans SC, so Chinese renders without mojibake, and table borders plus automatic pagination keep even a sixty-line order readable.
Batch export is a hard requirement in e-commerce, such as exporting the day's order confirmations for warehouse printing. The frontend loops through the order list, calls addPage per order, and saves once: one PDF containing every order, each starting on a fresh page. Printing and sorting become trivial, far more efficient than one-by-one operations.
For platforms and SaaS e-commerce tools, frontend generation has a hidden benefit: the template is the page. Operators can adjust the confirmation layout with a visual editor, and the change takes effect immediately because there is no server-side rendering pipeline to redeploy. Platforms can even expose the template as a merchant-configurable option, turning a routine document into a differentiator.
Supporting a fleet of merchant templates is also simpler in the frontend. Each merchant's configuration can be a small overlay on the default template, stored as data rather than code, so onboarding a new merchant never requires a deployment and the blast radius of a template bug stays limited to the affected store.
Arrange the template top to bottom: the order header with order number, time, and status; the shipping information block; the line-item table; the payment summary; payment and shipping details; and a notes area. Use clear borders and whitespace between sections so information never piles up illegibly.
The line-item table should have columns for sequence, product name, specification, unit price, quantity, and subtotal, with a wide product-name column. Below the table, show goods total, shipping, discount, and the amount paid, with the paid amount bolded so the customer sees the final figure at a glance.
Show receiver, phone, and address in a two-column layout, allowing long addresses to wrap. Right-align the payment area and keep two decimal places. If the customer left a note or needs an invoice, render that in a separate block at the bottom, spaced from the body so nothing sticks together when printed.
Give the payment summary area special attention: align goods total, shipping, discount, and amount paid in four tidy rows, and make the paid amount larger and bolder. If the order used a coupon or tiered discount, add a short note next to the discount line, such as 30-off-over-300, so customers understand where the savings came from and stop questioning the math.
Reserve a clean area for notes and invoice information. Many orders carry delivery instructions, gift messages, or invoice titles; rendering them in a dedicated block keeps the body of the document uncluttered and ensures nothing important is hidden inside a long product list.
This example walks through the complete order confirmation flow, from order data to PDF file. Line items are generated in bulk with a map call, and the payment area is laid out separately to emphasize the amount paid.
Note how amounts are handled: the line subtotal is unit price times quantity, but the total paid comes directly from the backend. Never recompute the payable total in the frontend, because coupon allocation and tiered discounts have complex rules and frontend recalculation invites cent-level discrepancies.
In the example the order object is defined inline, but in production it comes from the ordering API with different field names. Map the API fields to the template's expected structure at the entry point of the template function, so the template stays stable and only the thin mapping layer changes when the API evolves.
Product specifications may be empty for some items, such as products without color or size options. Check for empty values before rendering and display a dash or leave the cell blank, so the PDF never shows an undefined string. Quantities should be integers and amounts should carry two decimals, and normalizing these in the data layer keeps every order document clean.
If the order includes free gifts, list them in a separate section below the table and mark their value as zero. Gifts stay visible for the customer's delight and the warehouse's accuracy, while the totals remain untouched and reconciliation stays straightforward.
import { DomPDF } from 'dompdf.js';
const order = {
id: 'SO202608180001',
time: '2026-08-18 14:30:22',
receiver: 'Zhang Xiaoming',
phone: '138****1234',
address: 'No. 88 XX Road, Zhangjiang Hi-Tech Park, Pudong, Shanghai',
items: [
{ name: 'Wireless Earbuds Pro', spec: 'White', price: '399.00', qty: 1 },
{ name: 'Fast Charger 65W', spec: 'Black', price: '89.00', qty: 2 },
{ name: 'Phone Stand', spec: 'Aluminum', price: '29.90', qty: 1 },
],
freight: '0.00',
discount: '-20.00',
total: '497.90',
payMethod: 'Alipay',
carrier: 'SF Express',
};
const itemRows = order.items.map((item, i) => `
<tr>
<td style='border:1px solid #333;padding:6px;text-align:center'>${i + 1}</td>
<td style='border:1px solid #333;padding:6px'>${item.name}</td>
<td style='border:1px solid #333;padding:6px'>${item.spec}</td>
<td style='border:1px solid #333;padding:6px;text-align:right'>${item.price}</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${item.qty}</td>
<td style='border:1px solid #333;padding:6px;text-align:right'>${(item.price * item.qty).toFixed(2)}</td>
</tr>
`).join('');
const orderHtml = `
<h1 style='text-align:center;font-size:16pt'>Order Confirmation</h1>
<p style='text-align:center;font-size:10pt'>Order No: ${order.id} Time: ${order.time}</p>
<div style='border:1px solid #333;padding:8px;margin:10px 0'>
<p style='margin:2px 0'>Receiver: ${order.receiver} ${order.phone}</p>
<p style='margin:2px 0'>Address: ${order.address}</p>
</div>
<table style='width:100%;border-collapse:collapse'>
<tr style='background:#f5f5f5'>
<th style='border:1px solid #333;padding:6px'>No.</th>
<th style='border:1px solid #333;padding:6px'>Product</th>
<th style='border:1px solid #333;padding:6px'>Spec</th>
<th style='border:1px solid #333;padding:6px'>Price</th>
<th style='border:1px solid #333;padding:6px'>Qty</th>
<th style='border:1px solid #333;padding:6px'>Subtotal</th>
</tr>
${itemRows}
</table>
<div style='text-align:right;margin-top:8px'>
<p style='margin:2px 0'>Goods total: ${order.items.reduce((s, it) => s + it.price * it.qty, 0).toFixed(2)}</p>
<p style='margin:2px 0'>Shipping: ${order.freight} Discount: ${order.discount}</p>
<p style='margin:2px 0;font-weight:bold;font-size:12pt'>Amount paid: ${order.total}</p>
</div>
<p style='font-size:10pt;margin-top:8px'>Payment: ${order.payMethod} Carrier: ${order.carrier}</p>
`;
const pdf = new DomPDF();
pdf.addPage(orderHtml, { format: 'A4', margin: '20mm' });
pdf.save(`order-confirmation-${order.id}.pdf`);
Large or wholesale orders can contain dozens or hundreds of items. When one page is not enough, dompdf.js paginates automatically and repeats the header row on subsequent pages, so picking staff can still read the columns after flipping. Controlling row height and font size also fits more line items per page.
For batch export, loop over the order list in batches: build the HTML for each order, call addPage, and save once after all orders are added. Start each order on a new page so printed sheets can be separated by order, and put the order number in the header or footer for easy filing.
Watch memory usage in batch scenarios: for very large sets, process in chunks, for example one PDF file per 100 orders. Show a progress indicator so the page never appears frozen, and provide a download link when generation completes for a friendlier experience.
For warehouse printing, group orders by warehouse or shipping batch, generate the batch consecutively, and label the header with the batch number. Combined with the browser's one-click print dialog, the entire batch outputs in a single pass, and staff sort the sheets by page, which meaningfully speeds up fulfillment during peak periods.
Large batches also benefit from a progress indicator and a pause or cancel option. If a data problem surfaces mid-batch, stopping early beats generating a hundred wrong documents; fix the data, then regenerate only the affected slice instead of redoing everything.
Problem one: long product names break the table layout. Give the product-name column a fixed width and allow wrapping; never force nowrap, or long names will blow out the table and wreck the whole page layout.
Problem two: cent-level discrepancies. Multiplying price by quantity can introduce floating point errors. Convert amounts to integer cents for arithmetic before formatting, or use the backend subtotal directly, so the confirmation always matches the order system exactly.
Problem three: special characters in shipping addresses. Addresses may contain full-width characters, parentheses, and rare Chinese characters, all of which the built-in font renders fine. If something looks wrong, check HTML escaping so special symbols are not misinterpreted and break the structure.
Make the confirmation self-service: include customer service contact information and a summary of the return policy, plus a QR code linking to order tracking. Customers scan the code to check logistics themselves, which reduces support volume while making the document genuinely useful after the purchase moment.
Finally, keep a generation log mapping each PDF file to its order number. When a customer asks for a re-send or the warehouse loses a sheet, the log lets you reproduce the exact document in seconds, and it doubles as an audit trail for compliance-sensitive operations.
Keep an eye on performance when generating many confirmations at once. Building dozens of large HTML strings synchronously can jank the page; chunk the work with small delays or use a Web Worker if needed, and always give the user feedback while the batch is being produced.
Finally, plan for the edge cases that will happen: cancelled orders, split shipments, and partial refunds. Each should render a clear status on the confirmation rather than ambiguous wording, so the document never silently contradicts the order system.
下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:
这是由 dompdf.js 渲染的示例 PDF 内容。