Post

Docx Templating in JavaScript

In this guide we’ll look at how to create a docx template and fill out that document using JavaScript. We’ll do this by using the docxtemplater package. This works in both NodeJS and React.

  1. Installing Requirements
  2. The Code
  3. Filling out the Template with JavaScript
  4. Direct Values
  5. Styling
  6. Lists
  7. Table Rows
  8. Conditional Rendering
  9. Helpful Tips

Installing Requirements

Install the docxtemplater & pizzip packages using the following command:

1
npm i docxtemplater pizzip


The Code

The main code for all the below examples will stay the same. The only thing that will be changing is the dataToAdd Object (line 14). All other lines will stay the same.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const fs = require('fs');
const path = require('path');
const PizZip = require('pizzip');
const Docxtemplater = require('docxtemplater');

// Load the templated docx file
const templateFile = fs.readFileSync(path.resolve(__dirname, 'template.docx'), 'binary');
const zip = new PizZip(templateFile);

try {
	// Attempt to read all the templated tags
	let outputDocument = new Docxtemplater(zip);

	const dataToAdd = {};

	// Set the data we wish to add to the document
	outputDocument.setData(dataToAdd);

	try {
		// Attempt to render the document (Add data to the template)
		outputDocument.render()

		// Create a buffer to store the output data
		let outputDocumentBuffer = outputDocument.getZip().generate({ type: 'nodebuffer' });

		// Save the buffer to a file
		fs.writeFileSync(path.resolve(__dirname, 'OUTPUT.docx'), outputDocumentBuffer);
	}
	catch (error) {
		console.error(`ERROR Filling out Template:`);
		console.error(error)
	}
} catch(error) {
	console.error(`ERROR Loading Template:`);
	console.error(error);
}


Filling out the Template with JavaScript

All of the data that will be added to the template will be contained within a single Object called dataToAdd.

Each key in the dataToAdd Object refers to a tag that was placed in the docx file. Let’s see how to do this:

Direct Values

Direct values simply mean static values that we wish to insert into the document. Some examples would be the date, author, title. Simple text values you wish to add that may change with each document.

Docx File

The Code

1
2
3
const dataToAdd = {
    document_creation_date: (new Date()).toLocaleDateString()
};

Results


Styling

The style that is applied to the tag in the document will be inherited by the value that is inserted:

Docx File

The Code

1
2
3
4
const dataToAdd = {
    document_creation_date: (new Date()).toLocaleDateString(),
    document_author: 'Alexander Wells',
};

Results


Lists

A very useful feature is to be able to template repetitive sections. Perhaps the document is suppose to contain the profiles of some employees. Let’s see how we can use lists to do this:

Docx File

  • Lists are prefixed with the # character to start the list scope, and the / character to end the list scope.

The Code

1
2
3
4
5
6
const dataToAdd = {
    employeeList: [
        { id: 28521, name: 'Frank', age: 34, city: 'Melbourne' },
        { id: 84973, name: 'Chloe', age: 28, city: 'Perth' },
    ]
};
  • When using lists, the value should be a list of Objects.
  • The keys of each Object will refer to the tags used inside the List in the docx file (id, name, age, city).

Results


Table Rows

We can also use lists to create additional rows of a table. Let’s use the employee example again, but this time let’s use a table to represent the data:

Docx File

The Code

1
2
3
4
5
6
7
8
const dataToAdd = {
    employeeList: [
        { id: 28521, name: 'Frank', age: 34, city: 'Melbourne' },
        { id: 84973, name: 'Chloe', age: 28, city: 'Perth' },
        { id: 10349, name: 'Hank', age: 68, city: 'Hobart' },
        { id: 44586, name: 'Gordon', age: 47, city: 'Melbourne' },
    ]
};

Results


Conditional Rendering

Docx File

Another useful feature would be if we could only render certain things if a condition is met. Let’s see how we can do that:

The Code

1
2
3
4
const dataToAdd = {
    showDocumentAuthor: true,
    document_author: 'Alexander Wells',
};

Results

Changing showDocumentAuthor to false means the data inside the conditional statement won’t be rendered.


Helpful Tips

Too Much Spacing

You may notice if you use loops that extra spacing gets added where you don’t want. Let’s look at an example where this is very clear:

1
2
3
4
5
6
7
const dataToAdd = {
    groceryList: [
        { item: 'Eggs' },
        { item: 'Steak' },
        { item: 'Apples' }
    ],
};

  • With visible formatting enabled we can see the issue.
  • An extra line has been inserted between each list element.

We can fix this by enabling by enabling paragraphLoop option when creating our output document:

1
let outputDocument = new Docxtemplater(zip, { paragraphLoop: true });

Error Finding 1

  • One downside of this library is that error locations is actually a paid feature (yes I’m serious), look here.
  • This is an inconvenience and nothing more.
  • I STRONGLY suggest that you do templating in small batches. Add a few tags, test, add a few more, then test again.
  • Please do not spend hours (or even an hour) templating before testing. It will save you a massive headache when the program just says error, and you have to hunt through your document to find the issue.

Error Finding 2

  • Ensure that your tags in the docx file do not contain spaces at the start or end.
  • If you have a list tag called {#employeeList}, ensure there is no whitespace like this {#employeeList }, as this can cause the program to fail.
  • Microsoft Word can automatically add spaces so be aware of that.

Tag Names

  • USE GOOD TAG NAMES!
  • Just like when programming you try and use good variable names, same goes here.
  • A large document may have dozens or hundreds of tags. Using date for a tag name is BAD!
  • Using document_creation_date is much better as it’s clear exactly what date it’s referring to.
This post is licensed under CC BY 4.0 by the author.