You are currently offline, serving cached version


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

Usage (nodejs)

const XlsxModule = require("docxtemplater-xlsx-module");

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

const buffer = doc.getZip().generate({
    type: "nodebuffer",
    compression: "DEFLATE",

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

Usage (browser)

    <script src="node_modules/docxtemplater/build/docxtemplater.js"></script>
    <script src="node_modules/pizzip/dist/pizzip.js"></script>
    <script src="node_modules/pizzip/vendor/FileSaver.js"></script>
    <script src="node_modules/pizzip/dist/pizzip-utils.js"></script>
    <script src="build/xlsxmodule.js"></script>
        const xlsxMime =

            function (error, content) {
                if (error) {

                const zip = new PizZip(content);
                const doc = new docxtemplater(zip, {
                    modules: [new XlsxModule()],

                    name: "John Doe",
                const out = doc.getZip().generate({
                    type: "blob",
                    mimeType: xlsxMime,
                saveAs(out, "generated.xlsx");



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.render({average: 10.5})
  • For string, you can use Javascript strings, eg doc.render({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.render({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.render({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.render({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.render({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.render({date: {type: "date", value: new Date(1561799335622), /*29th June 2019*/ fmt: "DD/MM/YYYY"}})

  • For formulas, you can use the following : doc.render({computation: {type: "formula", value: "A1+B1"}});.


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 this data :

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

will render as :

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

The innerLoopNewLine option can be used to disable insertion of newlines inside innerloops.

Set this option to false to disable the insertion of newlines.

const doc = new Docxtemplater(zip, {
    modules: [
        new XlsxModule({
            innerLoopNewLine: false,
    users: [
        { name: "John" },
        { name: "Mary" },
        { name: "Franck" },

With the following template :

| {#users}{name}{/} | xxx |

Will render

| JohnMaryFranck | xxx |

Horizontal loop (or expansion)

You can, since version 3.5.0, expand an array horizontally :

Users are      | {>users}{name} |
Ages are       | {>users}{age} |

with this data :

    "users": [
        { "name": "John", "age": 22 },
        { "name": "Mary", "age": 29 },
        { "name": "Dave", "age": 41 }

will render as :

Users are      | John | Mary | Dave |
Ages are       | 22   | 29   | 41   |

Note that the cells on the right of the horizontal loop will be pushed (but only those that are on the same line of course).

Default Formats

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

To do it, use the fmts option in the constructor 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 doc = new Docxtemplater(zip, {
    modules: [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 :

const XlsxModule = require("docxtemplater-xlsx-module");
const expressionParser = require("docxtemplater/expressions.js");

expressionParser.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 = {
                    [property]: subtarget,
                const newLines = recur(
                output = output.concat(newLines);
        return output;

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

const doc = new Docxtemplater(zip, {
    modules: [new XlsxModule()],
    parser: expressionParser,

Height of rows

The height of rows is updated by the module and tries to use an algorithm optimized for Microsoft Exce.

It is possible that if you open generated files using other software, such as libreoffice or WPS, the rendering of the text inside the rows will make the row not high enough to contain the whole text.

This is because the margin between text in a row is not specified in the document itself and is dependent on the software used for rendering the sheet.

For this reason, it is possible to change the algorithm used for calculating the height of the row.

const doc = new Docxtemplater(zip, {
    modules: [
        new XlsxModule({
            getRowHeight({ lines, fontSize }) {
                return Math.round(lines * (fontSize + 3) + 1.4);
    users: [
        { name: "John" },
        { name: "Mary" },
        { name: "Franck" },

The lines is the number of lines in that cell, and fontSize is the fontsize of the text in that cell.


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.



Update to allow creation of HTML-xlsx module


Performance bufix when using XLSX module with many cells in async mode.

In prior versions, the async version of docxtemplater would be twice slower than the sync version if all data getters resolved immediately.

Now, the async version should be faster than before.


Performance bugfix :

In prior versions, the xlsx module was taking a lot of time when generating over 50000 cells.

Previously the generation of 50000 cells could take up to 7 minutes, now it should normally take less than 5 seconds.


Bugfix to correctly apply the alignment property when having data with new lines.

In previous versions, if a cell was left aligned, if the data contained a new line, the rendered cell would be wrongfully left aligned.


Bugfix when used together with the image module :

If the image is an image that uses the "description" tag, and is present inside a loop, the image is now correctly replaced.

This module requires version 3.19.0 of the xlsx module or higher


Update to work well with new angular parser (from docxtemplater/expressions.js), when using {this} as a numeric value.

In previous versions, this value would be converted to a string and formatted as such.


If using a corrupt character in some value, throw an error during generation.

For example,

    name: `John${String.fromCharCode(0x02)}Doe`,

Will now fail, in the same way that it fails on docx or pptx documents.


Avoid possible issue of "Maximum call stack size exceeded"


Bugfix : Previously, every unclosed loop would show the error twice.

The template :


(with no closing tag) would show two errors.

Now the error is no more duplicated.


Calculate correct image size even when having merged cell


Remove the single quotes in sheetnames when parsing a range.


Update to add forceFullCalc="1" and calcCompleted="0" after generation


Add containerWidth and containerHeight attributes to image tags.


Bugfix following regression :

Could not parse position for square ''

When having a "#REF" in the printarea or printtitle


Update to make module compatible with docxtemplater@3.30.0

Fixes following error :

TypeError: Cannot read properties of undefined (reading 'droppedTagsInsidePlaceholder')
at parse (js/parser.js:170:46)


Bugfix corruption when having calcChain and some loops will "move" formulas.


Enhance height calculation of rows for loops + inner loops.

Add getRowHeight function to customize the height calculation


Bugfix corruption when using horizontal loop expand module with cells after Z. The previous version was generating a cell named "A@5", which is disallowed (the cell name after Z should be AA).


Bugfix corruption when using styles inside cells with placeholders.

Bugfix error when having an "infinite" range, like :

"$A:$K" or "$1:$10"

It gave the following error :

TypeError: Cannot read properties of null (reading '4')
at getPosition (docxtemplater-xlsx-module/js/xl-utils.js:41:23)


Bugfix corruption when using a cell that has multiple styles (for example partially bold), and that has a {placeholder} in it.


When used together with the image module 3.13.0 or higher, Add possibility to replace images in Excel documents (using the description field).


Update typing files to add new option innerLoopNewLine.


Add option innerLoopNewLine to disable insertion of newlines inside innerloops.


Bugfix escaping of special characters such as <, >, & in async mode (with renderAsync)


Improve rendering speed a lot (and minimize output size), when using loops that contain a lot of empty cells.

Sometimes, rows can contain up to 16000 cells :

<c r="O2"/>
<c r="P2"/>
<c r="EEA2"/>
<c r="EEB2"/>
<c r="EEC2"/>
<c r="EED2"/>
<c r="EEE2"/>


Bugfix to avoid this error when generating a document :

RangeError: Maximum call stack size exceeded


Bugfix related to 3.8.0

Whitespace in

doc.render({ name: "      John" });

will now be correctly rendered.

This will work both with spacing and newlines


Always render spaces in xlsx files. Previously, spaces such as the following would not be rendered (sometimes) :

doc.render({ name: "     John" });

By always ensuring the use of <t xml:space="preserve">, the spaces are now shown correctly.

Make module compatible with docxtemplater@3.28.0. Please make sure to update docxtemplater to 3.28.0 at the same time you update this module. The internal change made is the use of the new matchers API which fixes bugs that were triggered depending on the order of the modules that are attached to the instance. Now the order of the modules should not matter as expected.


Update to make module work well together with docxtemplater 3.27


Update to make module work well together with docxtemplater 3.26.3


Return errors properly when there is an unopened tag or an unclosed tag.

Previously, the error "Error !!" was raised, without any better explanation.


Add support for {@rawXML} tag to be able to add formatted text to a given cell.


When using a loop containing a mergecell, with no data, that would put the number of mergecells of the document to 0 (no more mergecells in that sheet), the resulting document would be corrupted.

Now, the document is no more corrupted in this case.


Use @xmldom/xmldom instead of xmldom, see this github issue


Generate files in built with correct filename In previous versions, the filename was always build/docxtemplater.js. Now the filename is build/xlsxmodule.js The .min.js file is also created now.


Avoid corruption of document when using {>user} tag followed by an empty cell (that is formatted for example but has no value inside it)

Fixes this github issue


Make it possible to insert XLSX formulas, by using the library like this :

doc.render({computation: {type: "formula", value: "A1+B1"}});


Make module work correctly when using docxtemplater >= 3.22.1 with ">", "<", …

Add typescript definitions for public API


Bugfix when having multiple merge cells inside a loop, fixes this bug report.


Bugfix when using multiple loops on same line, for example on :

| {#loop}{#cond} | {name} | {/cond}{/loop} |

Previously, this would generate the message : The tag "loop" is closed by the tag "cond"


Add horizontal loop feature with ">" prefix.

Fixes this github issue


Bugfix printarea when using async mode (with resolveData)

The stacktrace was :

TypeError: Cannot read property 'toString' of undefined
at getResolvedId (docxtemplater-xlsx-module/js/index.js:100:47)


Automatically update printarea when having loops


Bugfix to make Image replacement work in async mode (you need access to both modules image and xlsx)


Add support for ImageModule together with XLSXModule to insert images with {%image} (you need access to both modules)


Bugfix to allow to have loop at the right of a merged cell, and have the merged-cell auto expand.


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
   at XlsxModule.createFormat (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 this 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
Talk with sales