Skip to main content

DOCX Templates

DOCX templates let you author in Microsoft Word (or LibreOffice Writer) and keep a fully editable layout. Velkin fills Handlebars placeholders directly in the document's OOXML, then either returns the native .docx or converts it to PDF via LibreOffice.

Asset extension.docx
EngineHandlebars.js 4.7.8 (goja VM), preprocessed on word/document.xml
RendererNative fill, or LibreOffice (soffice) → PDF
Endpointsrender-docx (native), render-pdf (converted)

How it works

A .docx is a ZIP of OOXML parts. When you render, Velkin:

  1. unzips the document;
  2. rejoins Handlebars tags that Word split across formatting runs;
  3. promotes block markers that sit alone in a row or paragraph so the loop or condition wraps the whole row/paragraph;
  4. runs the document XML through Handlebars with your data;
  5. re-zips the parts and returns the result.

Placeholders

Type Handlebars tags straight into the document text:

Invoice #{{number}}
Bill to: {{customer.name}}
Issued: {{date}}

Nested fields use dotted paths ({{customer.address.city}}), exactly as in HTML templates.

Type tags in one pass

Word silently splits text into multiple "runs" when formatting changes mid-word, which can fragment a tag like {{amount}} into {{amo + unt}}. Velkin rejoins split runs before substituting, so this usually just works — but you'll have the fewest surprises if you type each tag in one go and clear stray formatting inside it (select the tag → Clear Formatting).

Loops and conditionals

{{#each}} and {{#if}} work across paragraphs and table rows. The trick is where you place the markers: put the opening and closing tags alone in their own row or paragraph, and Velkin promotes them to wrap everything between.

In a table — opening tag alone in a row, the repeated content in the next row, closing tag alone in a row:

┌─────────────────────────────────────┐
│ {{#each items}} │
├──────────────────┬──────────────────┤
│ {{description}} │ {{amount}} € │ ← repeated once per item
├──────────────────┴──────────────────┤
│ {{/each}} │
└─────────────────────────────────────┘

In body text — each marker on its own paragraph:

{{#if overdue}}
This invoice is overdue. Please pay immediately.
{{/if}}

Helpers & partials

The report's helpers.hbs works inside DOCX templates exactly as in HTML: it's JavaScript, so register helpers and partials with Handlebars.registerHelper / Handlebars.registerPartial and invoke them with {{helperName arg}} / {{> name}}. See Helpers & Partials.

Escaping is off for OOXML

On the DOCX/XLSX pipelines Handlebars runs with HTML-escaping disabled, because the document XML is already entity-encoded. A helper that returns markup won't be double-escaped — but it also won't be sanitized, so keep helper output to plain text and values.

Native vs PDF output

  • render-docx returns the filled-in .docx — editable, fonts and layout exactly as authored.
  • render-pdf fills the template and converts to PDF with LibreOffice. Use it for a non-editable artefact.

In the Studio, the preferredOutput setting (native / pdf) only decides which of these the download button calls — see Output formats.

Fonts in PDF conversion

PDF conversion runs through the LibreOffice bundled in the backend image. If a font used by your template isn't installed there, LibreOffice substitutes the closest match, which can shift layout. Install the fonts you need in the backend image, or stick to widely available families.