Releases RSS Feed
Compatibility : nodejs and browser

Summary (version 3.3.6) Buy xlsx module

This module makes it possible to do templating on xlsx. It allows to do simple replacements and also loops.



You will need docxtemplater npm install docxtemplater

Install this module with npm install --save "$url"


By using this module, you add support for the xlsx format (Excel format) that allows you to use placeholders in xlsx documents.

It supports rendering values as :

  • Floats/Integers, eg 10 or 10.5
  • Strings, eg Category
  • Percents, eg 33.5% for a value of 0.335
  • Dates, eg 06/29/19 when using a javascript Date object
  • Currency, eg $15.00 for a value of 15
var XlsxModule = require("docxtemplater-xlsx-module");

var xlsxOpts = {};
var xlsxModule = new XlsxModule(xlsxOpts);

var content = fs.readFileSync("demo_template.xlsx");
var zip = new PizZip(content);
var doc = new Docxtemplater()
    name: "John Doe",
    totalPrice: {
      type: "currency",
      value: 100,
    discount: {
      type: "percent",
      value: 0.195,

var buffer = doc
  .generate({ type: "nodebuffer", compression: "DEFLATE" });

fs.writeFile("output.xlsx", buffer);


To work with "typed" data, (dates, percents, etc, you will have to use the following :

Basic types

  • For floats and integers, you can use Javascript floats or integers, eg doc.setData({average: 10.5})
  • For string, you can use Javascript strings, eg doc.setData({customerName: "John Doe"})

Complex types

For all complex types, you should use an object for representing them.

The object should contain a key type (string) representing the name of the type. The object should contain a key value representing the value of the type. The object can contain a key fmt representing how to represent that type (for example, how many leading zeroes, how many numbers after the dot).

  • For Percents, the type is "percent" and the value a number where 1 maps to 100% and 0.5 maps to 50%. For example : doc.setData({discount: {type: "percent", value: 0.10}}) to represent the number 10%

  • For Currencies, the type is "currency" and the value a number. For example : doc.setData({price: {type: "currency", value: 200}}) to represent the value $200. It is possible to change the currency by using a custom format, for example : doc.setData({price: {type: "currency", value: 200, fmt: "#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]"}}) to represent the value 200 €

  • For dates, you can use the date object in javascript, For example : doc.setData({today: new Date()}) will show you the current date formatted as "MM/DD/YY". You can also use the "object notation" to specify a custom format : doc.setData({date: {type: "date", value: new Date(1561799335622), /*29th June 2019*/ fmt: "DD/MM/YYYY"}})


It is possible to use loops with the syntax :

{#items} | {name} | {quantity} | {price} | {/items}

With following code :

// doc = new Docxtemplater()
// ...
  items: [
      name: "Product A",
      quantity: 5,
      price: {
        type: "currency",
        value: 10,
      name: "Product B",
      quantity: 1,
      price: {
        type: "currency",
        value: 20,

The beginning and the end of the loop must be on the same row, but not on the same cell (if the loop start is on the same cell as the loop end, docxtemplater will compile it to a "innerloop", see below).


If the beginning and the end of the loop are on the same cell, the row is not repeated but rather just the content inside that cell.

For example :

{#items} {name} | {#tags}{value} |  {quantity} | {price} | {/items}
                | {/}            |             |         |

with the data

  "items": [
      "name": "AcmeSoft",
      "tags": [{ "value": "fun" }, { "value": "awesome" }],
      "quantity": 10,
      "price": {
        "type": "currency",
        "value": 100

will render as :

AcmeSoft | fun      | 10 | $100 |
         | awesome  |    |      |

Default Formats

It is possible to change the default formats for currencies, percents, dates.

To do it, use the fmts option in the opts of the module

For example :

const xlsxOpts = {
  fmts: {
    float: "0.0",
    currency: "#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]",
    date: "DD/MM/YYYY",
    percent: "0.0%",
const xlsxModule = new XlsxModule(xlsxOpts);

Nested subloops on same line

It is possible to loop over multiple layers of your data structure and still have exactly one line for each recursive loop.

For example, with following data structure :

      "name": "Plan 1",
      "price": "800 $",
      "product": [
          "name": "Awesome table",
          "quality": [
              "name": "Blueish"
              "name": "Gray"
          "name": "Fun Jigsaw",
          "quality": [
                "name": "Easy",
                "name": "Difficult",

You can generate following file :

Plan 1 | 800 $ | Awesome table | Blueish
Plan 1 | 800 $ | Awesome table | Gray
Plan 1 | 800 $ | Fun Jigsaw    | Easy
Plan 1 | 800 $ | Fun Jigsaw    | Difficult

By using following template :

{#plans | subloop:’product.quality’}{name} | {price} | {product ? : ‘’} | {quality ? : ‘’}    {/}

and following code :

function angularParser(tag) {
  if (tag === ".") {
    return {
      get(s) {
        return s;
  const expr = expressions.compile(tag.replace(/(’|“|”|‘)/g, "'"));
  return {
    get(s) {
      return expr(s);

expressions.filters.subloop = function (input, filters) {
  function recur(fullLine, targetedLine, properties, output) {
    if (properties.length === 0) {
      return fullLine;
    const property = properties[0];
    if (!targetedLine[property]) {
    if (targetedLine[property].length === 0) {
    if (targetedLine[property].length > 0) {
      targetedLine[property].forEach(function (subtarget) {
        fullLine = { ...fullLine, [property]: subtarget };
        const newLines = recur(fullLine, subtarget, properties.slice(1), []);
        output = output.concat(newLines);
    return output;

  return input.reduce(function (output, line) {
    return recur(line, line, filters.split("."), output);
  }, []);

var docx = new Docxtemplater()
  .setOptions({ parser: angularParser });


With the xlsx module, when using loops, the cells under them will be moved down so that do not get "overwritten" by the loop. However the formulas in the cells are not rewritten, as this would require a much more complex algorithm.



Bugfix when having table with filters with loops.

In previous versions, the filter would not apply to the newly created rows.

Now, it does apply to all rows, ie the table is expanded when adding data.


Performance improvements for big loops.

Loops of more than 5000 elements will now be significantly faster.


Fix xlsx module to work with docxtemplater 3.18.2.

If you use docxtemplater 3.19.0 or higher, you have to use docxtemplater-xlsx module 3.3.4 or higher or you will see some rendered values duplicated at multiple points in the generated spreadsheet.


Bugfix issue "Cannot read property 'type' of null" when using null value in a cell


Add support for templating headers and footers.


Bugfix corruption when using xlsx table with multiline header


Add support for inverted loops (to show a cell if a value is falsy), for example :

| {^show_vat} VAT DOES NOT APPLY {/} |


Avoid corruption when using array formulas (For example <f t="array" ref="C3"/>)


Add fullCalcOnLoad="1" to force recalc when opening file on Excel. (This does not work on Libreoffice)


Preserve height of rows if there is no placeholder within the cell

This avoids the following error that would occur previously:

TypeError: Cannot read property 'setAttribute' of undefined
 &nbsp; &nbsp;at XlsxModule.createFormat (/node_modules/docxtemplater-xlsx-module/js/index.js:513:18)


Declare supportedFileTypes, which allows to use this module with the new docxtemplater constructor which was introduced in docxtemplater 3.17.


  • Bugfix to use format specified in cell when converting string cell to int, instead of taking the "General" format, even when cell contains specific styles such as borders


  • Bugfix to use format specified in cell when converting string cell to int, instead of taking the "General" format


  • Bugfix when having <, >, or & in a tablecell


  • Reuse same style of existing cell as much as possible (keep borders, font-sizes, colors, …)
  • Handle the case of implicit numFmtId


  • Avoid corruption for multiline content in a single cell


  • Add support for having multiple conditions inside a single cell, for example : {#cond1}foo{/cond1}{#cond2}bar{/cond2}
  • Keep font-style (bold, italic, …) from cell when converting to a numeric cell.
  • Allow nested inner loops, for example : {#cond1}{#cond2}{text}{/}{/}


  • Bugfix when having merged cells beyond AA, the end of the merge cell was reversed (for example "AC1:AG2" would be transformed into "AC1:GA2"


  • Bugfix when having merged cells beyond AA , for example between Z1 and AA5, the document was corrupted
  • Bugfix when having excel file which has only formulas (no static content), the module was throwing an error Cannot read property 'getElementsByTagName' of undefined at XlsxModule.addXmlDocuments
  • Bugfix when having excel file which had a dragged formula, the module was throwing an error Cannot read property 'value' of undefined at XlsxModule.postparseSimple.


Bugfix when having multiple merge cells within multiple sheets, the renderer would produce corrupt spreadsheets.

Bugfix when having a formula which value computes to "" (an empty string), the following error was shown : Cannot read property 'value' of undefined , at XlsxModule.postparseSimple


Make sure numFmt is added as the firstchild of stylesheet in styles.xml


Update to work with latest docxtemplater, version 3.15.4


Update module to work with docxtemplater 3.15.1 and above


Multiple improvements for loops and styles

Add support for merged cells inside loops, and before or after loops


Add support for xlsm filetype


  • Bugfix when using this module on a docx document, this no more fails.

  • Bugfix when creating XLSXModule without any option (a stacktrace was shown in 3.0.0)


  • Initial release

Edgar Hipp

I'm the creator of docxtemplater. I work on making docxtemplater great since 2013.