Authoring HTML Templates¶
Document templates are HTML files with embedded CSS. The backend renders them using the Handlebars/Mustache engine and converts the result to PDF.
Technical constraints¶
Warning
The PDF renderer supports HTML 4 and CSS 2.2 only. Modern CSS features are not supported.
- Use
table/tr/tdfor layout - Do not use
flexbox, CSS Grid, or CSS variables - Do not use
position: fixedorposition: absolutefor content (headers/footers are an exception — see below) - External fonts must be embedded or referenced from a stable CDN
File structure¶
document-template/files/{businessClassTypeCode}/quote-template.html
document-template/files/common/pageHeader.html
document-template/files/common/insurerInfo.html
Full templates live in the business class subdirectory. Shared components (headers, footers, insurer details) live in files/common/ as partial templates.
Template skeleton¶
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
body { font-family: Arial, sans-serif; font-size: 10pt; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #1565C0; color: white; padding: 4px 8px; }
td { padding: 4px 8px; border-bottom: 1px solid #e0e0e0; }
</style>
</head>
<body>
{{>pageHeader}}
<h1>Quote Slip</h1>
<table>
<tr><th>Field</th><th>Value</th></tr>
<tr><td>Insured</td><td>{{risk.insuredParty.company.displayName}}</td></tr>
<tr><td>Inception Date</td><td>{{dateFormat risk.inceptionDate "dd/MM/yyyy"}}</td></tr>
<tr><td>Expiry Date</td><td>{{dateFormat risk.expiryDate "dd/MM/yyyy"}}</td></tr>
<tr><td>UMR</td><td>{{risk.umr}}</td></tr>
</table>
{{>pageFooter}}
</body>
</html>
Data mapping¶
Handlebars placeholders are replaced with risk data at render time. Data is available from several sources:
Risk and policy data¶
{{risk.inceptionDate}}
{{risk.insuredParty.company.displayName}}
{{policyGroup.policies.0.machinePrice}}
{{policyGroup.policies.0.additionalProperties.commissionPercentage}}
policyGroup.policies.0 accesses the first policy. Use array index notation to access specific policies.
Data capture screen data¶
Data entered by the user at the data capture step:
{{quote_document_generation.data.releasedBy.name}}
{{quote_document_generation.data.brokerDetails.office}}
The path format is: {operationName}.data.{fieldKey}. The fieldKey must match exactly what is defined in the screen meta data file.
Note
Only capture data on the data capture screen that is not available from the risk or policy object. Data available via {{risk.*}} or {{policyGroup.*}} does not need to be re-captured on the data capture screen — doing so creates a maintenance burden and risk of mismatched values.
Document clauses¶
Loop over clauses from a specific operation:
{{#forms_and_subjectivities.FORM}}
<p><strong>{{code}}</strong> — {{title}}</p>
<p>{{description}}</p>
{{/forms_and_subjectivities.FORM}}
{{#forms_and_subjectivities.SUBJECTIVITY}}
<p>{{code}} — {{title}}</p>
{{/forms_and_subjectivities.SUBJECTIVITY}}
{{#forms_and_subjectivities.OTHER}}
{{{formattedHtmlString}}}
{{/forms_and_subjectivities.OTHER}}
Note
Use triple braces {{{ }}} for the OTHER category, as it contains raw HTML that must not be escaped. Single or double braces would escape the HTML and display it as plain text.
Filtering clauses by sub-category¶
To loop over only a subset of clauses filtered by sub-category code:
{{#each (filterLoop document_creation.FORM "subCategory" "sc_clause_one") }}
<p>{{code}} — {{title}}</p>
{{/each}}
Partial templates¶
Reference shared partial templates with:
Partial files are stored in document-template/files/common/ and must be registered as PARTIAL type in the database. See Partial Templates.
Tips¶
- Test your template with a real risk that has all the expected data populated, to confirm all placeholders resolve correctly
- If a Handlebars placeholder renders blank, the most common cause is a path mismatch — compare the placeholder path against the actual risk JSON from
GET /v2/risks/{id} - Keep CSS minimal and inline where possible — the PDF renderer handles inline styles more reliably than class-based styles in some edge cases
- Use
{{now}}to insert today's date (the date of document generation, not the risk inception date)