Generate PDFs from a Word template using JavaScript
Nutrient Web SDK makes it easy to generate PDF documents from Word templates by dynamically merging them with data. You can run this process headlessly in the background or through our intuitive document viewer UI.
Overview
This guide walks you through creating PDFs from Word templates by:
-
Preparing DOCX templates with placeholders
-
Populating those templates with structured data
-
Exporting to PDF or PDF/A formats
General principles
Word templating consists of the following elements:
-
A DOCX file that will be used as the template.
-
A template model that contains the placeholder values to replace in the DOCX template.
-
Configuration for the template and model.
Template model
The template model can be an external JSON file or it can be created programmatically. It must contain:
-
A configuration containing a start delimiter and an end delimiter.
-
At least one placeholder-value pair. The placeholder name must correspond to the placeholder defined in the DOCX template.
Classes, methods, and properties
Populating a Word template
Nutrient Web SDK supports replacing placeholder text strings, loops, and dynamic tables. As the amount of content changes, the DOCX template will seamlessly adjust and reflow across pages as needed. Placeholders maintain their initial formatting from the DOCX template.
The first step is to prepare the DOCX template with placeholders. This example uses {{
and }}
as the delimiters to define the boundaries of placeholders.
Prepare the data:
const data = { config: { delimiter: { start: "{{", end: "}}" } }, model: { name: "Alex Smith", text: "Hello World!", amount: "$249.99" } };
Load the DOCX template and replace the placeholders in the DOCX template with the data and obtain the result as an ArrayBuffer
containing the resulting DOCX file:
const buffer = await PSPDFKit.populateDocumentTemplate( { // Other configuration options. document: "template.docx" }, data );
The following image shows what the DOCX file looks like.
Lastly, convert the DOCX file into a PDF. The following example converts it to PDF/A using the PDF/A-1a PSPDFKit.Conformance
level. However, you can choose whichever conformance enumeration you prefer:
const pdfBuffer = await PSPDFKit.convertToPdf( { // Other configuration options. document: buffer }, PSPDFKit.Conformance.PDFA1A );
Advanced example: looping through data sets
To create a loop, add an array of objects to the data model. For every object within the array, the loop’s body is replicated during each cycle of the loop when the DOCX and data model are processed. Here’s an example of such a data file:
const data = { config: { delimiter: { start: "{{", end: "}}" } }, model: { loop1: [ { loopDesc1: "Monday", loopDesc2: "Tuesday" }, { loopDesc1: "Wednesday", loopDesc2: "Thursday" }, { loopDesc1: "Friday", loopDesc2: "Saturday" } ], loop2: [ { loopDesc: "Red" }, { loopDesc: "Orange" }, { loopDesc: "Green" } ] } };
Below is an example of such a DOCX template.

For bulleted or numbered lists, the opening placeholder must immediately precede the start of the list, and the closing placeholder must immediately follow the end of the list.
Combining the data with the DOCX template produces the following output.

For an example of combining loops with tables, refer to the Dynamic Table Loop Example below.
Adding conditional logic
Conditionals allow a template to dynamically insert and format data based on conditions defined within the template itself. Conditionals can be combined with loops for more complex dynamic documents.
The template syntax for implementing conditionals uses special markers to denote the beginning and end of a conditional block, as well as to indicate the condition being tested:
-
#condition
— Marks the beginning of a block that should be rendered if the condition istrue
. -
^condition
— Marks the beginning of a block that should be rendered if the condition isfalse
(theelse
part). -
/condition
— Marks the end of a conditional block.
Here’s an example showing this syntax for an isBlue
condition:
{{#isBlue}}Blue{{/isBlue}}{{^isBlue}}Red{{/isBlue}}
{ config: { delimiter: { start: "{{", end: "}}" } }, model: { isBlue: true } }
Here’s a more complex example with conditionals.

It’s possible to combine the template above with the following data:
{ config: { delimiter: { start: "{{", end: "}}" } }, model: { isConsulting: false, consultingField: "N/A", scopeExhibit: "Exhibit A", startDate: "March 1, 2024", endDate: "February 28, 2025", autoRenew: true } }
In this case, the output will be the following DOCX, which can then be converted to PDF.

Dynamic table loop example
This example shows three different approaches to using loops for dynamically inserting rows into a table. You can download the DOCX template used in this example.

Using a model loaded from a JSON file
In this first approach, you’ll populate the DOCX template with data from a JSON file. You can download the JSON file used in this example:
const data = await fetch("table.json").then((response) => response.json() ); const docx = await PSPDFKit.populateDocumentTemplate( { // Other configuration options. document: "table.docx" }, data ); const pdfBuffer = await PSPDFKit.convertToPdf( { // Other configuration options. document: docx }, PSPDFKit.Conformance.PDFA1A );
Automatic reflow example
Text reflow refers to the automatic adjustment of text within a document or display area to ensure it fits within the given space without overflowing or leaving excessive empty space. This process involves moving words and characters to new lines, pages, or columns as needed based on the available width and height of the display area, the font size, and other formatting settings.

Here’s the JSON you’ll use:
{ "config": { "delimiter": { "start": "{{", "end": "}}" } }, "model": { "clauses": [ { "clause": "Lorem ipsum dolor sit amet, consectetur adipiscing elit..." }, { "clause": "Lorem ipsum dolor sit amet, consectetur adipiscing elit..." }, { "clause": "Lorem ipsum dolor sit amet, consectetur adipiscing elit..." }, { "clause": "Lorem ipsum dolor sit amet, consectetur adipiscing elit..." }, { "clause": "Lorem ipsum dolor sit amet, consectetur adipiscing elit..." } ], "title": "Purchase and Sale Agreement" } }
The example below shows how to generate a PDF from a DOCX template where the content is reflowed into another column by using a data model loaded from a JSON file. For an example of how to create the model programmatically, refer to the Dynamic Table Loop Example above:
data = await fetch("data.json").then((response) => response.json()); const docx = await PSPDFKit.populateDocumentTemplate( { // Other configuration options. document: "reflow.docx" }, data ); const pdfBuffer = await PSPDFKit.convertToPdf( { // Other configuration options. document: docx }, PSPDFKit.Conformance.PDFA_1A );