How-to guide
How to create a branded PDF template
Build a reusable DocForge template with brand styling, readable Liquid variables, and preview checks for real data.
What you'll need
Supplies
- Brand colors and logo guidance
- Example document copy
- Sample CSV or payload
Tools
- DocForge template builder
- HTML and CSS editor
Steps
- 1
Start with the document job
Start by writing the job of the PDF in one sentence, then build every section around that job. For an invoice, the job is to get the recipient to verify charges and pay on time. For an offer letter, it is to confirm role, start date, salary, and signature details without ambiguity. For a statement, it is to explain account activity clearly. Create a small field list before opening the template editor, such as `document_number,recipient_name,document_date,total_due,due_date,contact_email`. Keep internal-only fields out unless the reader needs them. A common mistake is designing around a perfect sample row, then discovering that `recipient_name` can be `Northwest Regional Distribution Holdings LLC`. Decide where long names wrap before styling. Use plain Liquid placeholders like `{{ row.recipient_name }}` and `{{ row.document_date | date: '%B %-d, %Y' }}` so the document structure stays tied to the data the batch will actually provide.
- 2
Define variables in plain language
Name variables the way an operator would say them during a handoff. Use `customer_name`, `billing_address`, `statement_month`, and `account_balance`, not `custNm`, `addr1_full`, or `bal_amt_final`. The variable names become the map between the CSV, the template, and the preview screen, so readable names reduce mistakes during busy batch work. A practical starting CSV for a branded statement is `statement_number,customer_name,statement_month,opening_balance,charges,payments,closing_balance`. Match those headers directly to Liquid values such as `{{ row.statement_number }}` and `{{ row.closing_balance }}`. Fix blank optional fields in the template instead of relying on every CSV export to be perfect. For example, use `{{ row.account_manager | default: 'Customer Support' }}` when the contact owner is optional. Preview a row with a missing `account_manager` and a row with a named owner like `Jamie Park` so both layouts look intentional.
- 3
Apply brand styling carefully
Apply brand styling after the content and variables are stable. Put the logo, colors, headings, table borders, and footer treatment around real data, not placeholder text. A clean invoice table with `item_summary,quantity,unit_price,line_total` behaves differently when one row says `Annual support plan` and another says `Rush replacement parts for West Dock compressor station`. Keep typography conservative, leave room for wrapping, and make totals easy to scan. Do not depend on a custom currency filter in the production PDF. Format currency values before upload, or pass clean strings such as `4250.00` and label the currency in the template. If the CSV mixes `4250`, `$4,250.00`, and `EUR 4250.00`, normalize it before upload so the rendered document does not look assembled from different systems. Preview the longest address, the largest total, and one row with an empty optional note using `{% if row.note %}{{ row.note }}{% endif %}`.
- 4
Preview with real rows
Preview with rows that represent the batch, not just the tidy demo record. For a branded document set, include one normal row, one long-name row, one missing-optional-field row, one large-number row, and one row with multi-line address data. A useful test CSV might include `document_number,recipient_name,billing_address,document_date,total_due,notes`. Check every placeholder against the source row. If `{{ row.total_due }}` shows blank, fix the mapping before touching layout. If `{{ row.document_date | date: '%B %-d, %Y' }}` renders incorrectly, normalize dates to ISO format such as `2026-06-30`; avoid mixed values like `30/06/26`, `6/30/2026`, and `June 30`. Look at the rendered PDF as the recipient would see it: logo placement, page breaks, footer contact details, and table overflow. Once the preview set passes, save that CSV as the test fixture for future template changes.