Skip to content

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 / td for layout
  • Do not use flexbox, CSS Grid, or CSS variables
  • Do not use position: fixed or position: absolute for 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:

{{>pageHeader}}
{{>insurerInfo}}
{{>insurerCompanyInfo}}

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)