Template design

HTML + CSS Template Design for API PDF Rendering

Build templates that render clean PDFs every time. Learn layout patterns, variable placement, and print CSS rules for HookPDF.

Most PDF rendering problems are not API problems, they are template problems.

If your HTML template is inconsistent, your JSON payload can be perfect and the final PDF can still look broken. The best way to avoid that is to treat template design as part of your backend contract.

In HookPDF, the core flow is simple:

  1. Create a template with HTML + CSS.
  2. Place Handlebars variables where dynamic values should appear.
  3. Send JSON payload to the API with your template_id.
  4. Receive a PDF output through the render job flow.

This guide focuses on Step 1 and Step 2: building templates that are easy to maintain and stable in production.

Start with a document structure that matches real usage

Before adding variables, design the static skeleton first.

For example, an invoice template usually has:

  • A header (company, invoice number, date)
  • A billing block (customer information)
  • A line-items table
  • A totals section
  • Notes or footer

Build this structure with plain HTML first. Then add variables.

HTML
<section class="invoice-header">
  <h1>Invoice</h1>
  <div class="meta-row">Invoice No: {{invoice_number}}</div>
  <div class="meta-row">Issue Date: {{issue_date}}</div>
</section>

<section class="customer-block">
  <h2>Bill To</h2>
  <p>{{customer.name}}</p>
  <p>{{customer.address}}</p>
</section>

Why this works:

  • You keep semantic sections clear.
  • Designers and developers can read the template quickly.
  • Variable placement becomes obvious and predictable.

Use variable naming that mirrors your JSON

Your template and payload should read like two versions of the same object.

If your payload is:

JSON
{
  "customer": {
    "name": "Northwind Labs",
    "address": "42 Market Street"
  }
}

Then your template should use {{customer.name}} and {{customer.address}}.

Avoid ambiguous names like {{name}} if the document has multiple names (customer name, company name, contact name). Fully qualified paths reduce mistakes.

Render repeating rows with #each blocks

For invoices, statements, and usage reports, arrays are common.

HTML
<table class="line-items">
  <thead>
    <tr>
      <th>Description</th>
      <th>Qty</th>
      <th>Unit Price</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody>
    {{#each items}}
    <tr>
      <td>{{description}}</td>
      <td>{{quantity}}</td>
      <td>{{unit_price}}</td>
      <td>{{line_total}}</td>
    </tr>
    {{/each}}
  </tbody>
</table>

This keeps your template flexible without changing HTML when item count changes.

Keep CSS print-friendly and explicit

For PDF output, avoid relying on browser defaults.

CSS
@page {
  size: A4;
  margin: 20mm;
}

body {
  font-family: Arial, sans-serif;
  color: #0f172a;
  font-size: 12px;
  line-height: 1.45;
}

.line-items {
  width: 100%;
  border-collapse: collapse;
}

.line-items th,
.line-items td {
  border-bottom: 1px solid #cbd5e1;
  padding: 8px;
}

Practical tips:

  1. Set explicit page margins.
  2. Use fixed spacing system (4px/8px based scale).
  3. Keep contrast high for tables.
  4. Avoid huge shadows and animation-focused CSS.

Add a preflight checklist before saving template changes

Use this checklist every time you modify a template:

  • Are all required variables present in the HTML?
  • Are variable paths aligned with the JSON payload shape?
  • Does the table still render well with 1 item and 30 items?
  • Do long customer names wrap without breaking layout?
  • Are date and currency values already formatted as you expect?

Formatting values before sending JSON is usually safer than trying to fix formatting inside the template.

Use this template for free now

Start with this template in HookPDF and render your first PDF for free.

Use this template free

Next step after template design

Once your template is stable, the next phase is payload + API execution.

Read the full walkthrough:

Ready to move from prototype to production?

Create your account and generate your first API-driven PDF with HookPDF.

Get your API key