Table patterns

Dynamic tables in PDF (array data)

Learn how to render reliable dynamic PDF tables from JSON arrays using Handlebars #each in HookPDF templates.

Dynamic tables are usually the first place where PDF templates break.

Why? Because array length changes, text length changes, and developers often hard-code assumptions for only one dataset.

In HookPDF, the robust pattern is:

  • Keep table markup stable.
  • Feed rows through #each.
  • Keep JSON array shape consistent.

This article shows practical table patterns that stay predictable when data volume changes.

Flow diagram (array data -> dynamic rows -> PDF)

TEXT
Template table markup
  <tbody>{{#each usage_rows}} ... {{/each}}</tbody>
                |
                v
JSON payload
  usage_rows: [ { ... }, { ... }, ... ]
                |
                v
POST /v1/render
                |
                v
job_id + status: queued
                |
                v
GET /v1/reports/{job_id}
                |
                v
status: completed -> output_url -> PDF

1) Base table pattern with #each

HTML
<table class="usage-table">
  <thead>
    <tr>
      <th>Date</th>
      <th>Event</th>
      <th class="num">Count</th>
      <th class="num">Credits</th>
    </tr>
  </thead>
  <tbody>
    {{#each usage_rows}}
    <tr>
      <td>{{date}}</td>
      <td>{{event}}</td>
      <td class="num">{{count}}</td>
      <td class="num">{{credits}}</td>
    </tr>
    {{/each}}
  </tbody>
</table>

This template does not need to change if the array has 2 rows or 200 rows.

2) Matching JSON shape

JSON
{
  "usage_rows": [
    {
      "date": "2026-03-15",
      "event": "invoice_render",
      "count": 44,
      "credits": 44
    },
    {
      "date": "2026-03-16",
      "event": "invoice_render",
      "count": 38,
      "credits": 38
    },
    {
      "date": "2026-03-17",
      "event": "summary_export",
      "count": 12,
      "credits": 12
    }
  ]
}

The key rule is consistency. If template expects usage_rows, payload must always send usage_rows as an array.

3) Add stable table CSS for PDF output

CSS
.usage-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 10px;
}

.usage-table th,
.usage-table td {
  border-bottom: 1px solid #cbd5e1;
  padding: 8px;
  font-size: 12px;
}

.usage-table th {
  background: #f8fafc;
  text-align: left;
}

.usage-table td.num,
.usage-table th.num {
  text-align: right;
  white-space: nowrap;
}

Practical result:

  • Numeric columns remain aligned.
  • Large tables stay readable.
  • Page breaks are cleaner than ad-hoc styles.

4) Real render request for dynamic table report

BASH
curl -X POST "https://api.hookpdf.com/v1/render" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "1c24f959-8e1a-4a14-acc4-cf57b4e60e99",
    "payload": {
      "report_title": "Weekly Usage Summary",
      "period": "2026-03-11 to 2026-03-17",
      "usage_rows": [
        {
          "date": "2026-03-15",
          "event": "invoice_render",
          "count": 44,
          "credits": 44
        },
        {
          "date": "2026-03-16",
          "event": "invoice_render",
          "count": 38,
          "credits": 38
        }
      ],
      "totals": {
        "events": 82,
        "credits": 82
      }
    }
  }'

Response:

JSON
{
  "job_id": "8e70de8c-60fd-4f62-b9ec-2270a0c55f47",
  "status": "queued",
  "is_preview": false
}

Then check status with /v1/reports/{job_id} until completed.

5) Common mistakes with dynamic table data

  1. Sending object instead of array for usage_rows.
  2. Renaming payload keys without updating template variable paths.
  3. Mixing numeric and string formats in same column.
  4. Forgetting to right-align numeric cells.

6) Template review checklist for array-driven tables

  • Is every table row generated from one predictable array key?
  • Do row objects have a stable field schema?
  • Are numeric columns right-aligned and consistent?
  • Does template still look correct with very short and very long arrays?

Use this template for free now

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

Use this template free

Related guides

Ready to move from prototype to production?

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

Get your API key