You are currently offline, serving cached version

The HTML module currently supports:

  • <br>
  • <p>
  • <h1-h6> tags, <h1> translates to Title, <h2> translates to Header1, <h3> translates to Header2, because there is no concept of title in the body of HTML
  • <p>
  • <b>
  • <i>
  • <u>
  • <ul>, <ol> and <li> for ordered and unordered lists
  • <span>
  • <small>
  • <s>
  • <ins> and <del>
  • <strong>
  • <em>
  • <code>
  • <table>, <tr>, <td>, <tbody>, <thead>, <tfoot>, <th> tags
  • <a href="URL">Linktext</a>
  • <input type="checkbox"> and <input type="checkbox" checked>
  • <sub> and <sup>
  • <pre>, by using Courrier font and retaining all spaces
  • <img> only if including the imageModule too, by using base64 src
  • <svg> only if including the imageModule too, but this format is only readable on newer Word version : Microsoft Word, PowerPoint, Outlook, and Excel 2016 on Windows, Mac, Android and Windows Mobile. See this article for details about this feature
  • style="color: #bbbbbb" property
  • style="font-size: 30px" property
  • style="font-family: 'Times New Roman'" property
  • style="background-color: blue" property (or with rgb codes)
  • style="text-decoration: underline" property
  • style="padding-left: 30px"
  • style="width:33%; height: 50%;" (on td only)
  • style="text-align:justify" (or other values)
  • style="vertical-align: bottom" (on td)
  • style="border: none" (on table)
  • style="break-after:page"
  • style="break-before:page"
  • style="white-space:pre"

Important : This module only supports docx (Word documents), not pptx, see the html-pptx module if you want to include HTML inside Powerpoint presentations.

Usage (nodejs)

var HTMLModule = require("docxtemplater-html-module");

var zip = new PizZip(content);
var doc = new Docxtemplater(zip, {
    modules: [new HTMLModule({})],
}).render({ html: "<b>Hello</b>, Foo !" });

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

fs.writeFile("test.docx", 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/html-module.js"></script>
            function (error, content) {
                if (error) {

                var zip = new PizZip(content);
                var doc = new docxtemplater(zip, {
                    modules: [new DocxtemplaterHtmlModule({})],

                    html: "<p>Hello <b>John</b></p>",
                var out = doc.getZip().generate({
                    type: "blob",
                saveAs(out, "generated.docx");

Your docx should contain the text: {~html}. After installing the module, you can use a working demo by running node sample.js.

  • Any tag starting with ~ is used for inline HTML, such as : {~html} or {~inlineComment} which will use the "inlineComment" data
  • Any tag starting with ~~ is used for block HTML, such as : {~~html} or {~~styledTable} which will use the "styledTable" data

To be clear :

  • The {~inline} tag is used when you want to replace part of a paragraph. For example you can write :
My product is {~blueText} and costs ...

The tag is inline, there is other text in the paragraph. In this case, you can only use inline HTML elements (<span> , <b> , <i>, <u>\, …)

  • The {~~block} tag is used when you want to replace a whole paragraph, and you want to insert multiple elements

The tag is block, there is no other text in the paragraph. In this case, you can only use block HTML elements (<p>, <ul>, <table>, <ol>, <h1>)


It is possible to set options to the htmlModule.

Description of the options :

  • ignoreUnknownTags [default=false]: If this option is set to true, and the module finds an HTML tag that it doesn't handle, it will not fail but instead make as if the tag was of type <span>;
  • ignoreCssErrors [default=false]: If this option is set to true, all CSS errors are ignored and the library tries to parse the CSS with a best-effort algorithm;
  • styleTransformer makes it possible to rewrite the styles that are used by the HTML module, see below for an example;
  • sizeConverters makes it possible to change the ratio between px and dxa for different tags;
  • styleSheet makes it possible to add style to all HTML tags that are inserted.

To ignore all unknown tags:

var doc = new Docxtemplater(zip, {
    modules: [
        new HTMLModule({
            ignoreUnknownTags: true,

To remap the styles so that h1 maps to Heading1 (instead of the default Title)

function styleTransformer(tags, docStyles, opts) {
    tags.h1 = docStyles.Heading1;
    tags.h2 = docStyles.Heading2;
    tags.h3 = docStyles.Heading3;
    tags.h4 = docStyles.Heading4;
    tags.h5 = docStyles.Heading5;

    // Note that docStyles.Heading1 is a hardcoded value in the docxtemplater html code, it is exactly the same as writing :
    // tags.h1 = {
    //     type: "block",
    //     data: {
    //         pStyle: "Heading",
    //         props: [],
    //     },
    // }
    return tags;

var doc = new Docxtemplater(zip, {
    modules: [
        new HTMLModule({
            styleTransformer: styleTransformer,

If you want to remap h1 to an other paragraphStyle (w:styleId property in styles.xml), you can do the following :

function styleTransformer(tags, docStyles, opts) {
    if (opts.styleIds.indexOf("Titre1") !== -1) { = "Titre1";
    return tags;

To change the size of "padding-left":

var doc = new Docxtemplater(zip, {
    modules: [
        new HTMLModule({
            sizeConverters: {
                paddingLeft: 20,

This will make paddingLeft a little bit larger on word than the default (which is 15).

To add a global stylesheet

const htmlModuleOptions = {
    styleSheet: `
        h1 {
            font-size: 60px;
        span#foo {
            font-size: 30px;
            color: red;
var doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlModuleOptions)],

Reasons for not supporting pptx

This module handles only docx documents, not pptx.

The reason for that is that HTML maps well to docx because they use the same linear flow, eg elements are placed one after the other in the document. However PPTX documents have multiple slides, which are stored in different files, and each element is positioned absolutely in the slide. For example, in PPTX if you have a table element and a paragraph in the same slide, they need to be placed in two "different" blocks.

There is the HTML-pptx-module that handles HTML insertion for PPTX.

Support for images with <img>

To be able to replace the <img> tag, you have to also have access to the Image Module.

Then, you can do :

const HTMLModule = require("docxtemplater-html-module");
const ImageModule = require("docxtemplater-image-module");

const htmlModuleOptions = {
    img: {
        Module: ImageModule,
         * By default getSize returns the width and height attributes if both are present,
         * or 200x200px as a default value.
        getSize: function (data) {
            /* The html element, for example, if the data is :
             * '<img width="20" src="...">'
             * you will have :
             * data.element.attribs.width = '20'

            /* If the data is '<img style="width:200px;" src="...">'
             * '<img width="20" src="...">'
             * you will have
             * data.parsedStyle = [
             *   { property: "width", value: "200px"}
             * ]
             * on which you could do :
             * data.parsedStyle.forEach(function({ property, value}) {
             *     if(property === "width") {
             *          width = parseInt(value.replace(/px$/, ""), 10);
             *     }
             * });
            /* data.src is the arraybuffer of your image
             * (you could use the image-size library to to calculate the size)
             * (
            // data.part.value is 'myTag' if your tag is {~myTag}
            // You return an array in pixel (here we have width 50px and height 100px)
            return [50, 100];

var doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlModuleOptions)],

The <img> tag supports base64 and also urls, so for example, you can do :


Note that HTTP URLs in src will not work by default, you have to configure docxtemplater in async mode to do so.

You can use the following getSize function if you would like to use the same width and height as the image source.

import sizeOf from "image-size";
function getSize(img) {
    const buffer = new Buffer(img.src);
    const sizeObj = sizeOf(buffer);
    return [sizeObj.width, sizeObj.height];

You can also add a caption to the image if using image module 3.7.0 or above, and use the following :

const HTMLModule = require("docxtemplater-html-module");
const ImageModule = require("docxtemplater-image-module");

const htmlModuleOptions = {
    img: {
        Module: ImageModule,
        // By default getSize returns the width and height attributes if both are present, or 200x200px as a default value.
        getProps: function (data) {
            return {
                caption: {
                    text: `: ${data.element.attribs.title}`,

var doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlModuleOptions)],

Support for images in async support (for urls)

It is possible to add images with src="http://......" by using async docxtemplater.

You can customize the image resolver with the getValue function.

Here is an example showing how to retrieve the data form :

const fs = require("fs");
const https = require("https");
const http = require("http");
const url = require("url");
const Docxtemplater = require("docxtemplater");
const ImageModule = require("docxtemplater-image-module");
const HTMLModule = require("docxtemplater-html-module");
const PizZip = require("pizzip");

function base64DataURLToArrayBuffer(dataURL) {
    const stringBase64 = dataURL.replace(
    let binaryString;
    if (typeof window !== "undefined") {
        binaryString = window.atob(stringBase64);
    } else {
        binaryString = Buffer.from(
    const len = binaryString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        const ascii = binaryString.charCodeAt(i);
        bytes[i] = ascii;
    return bytes.buffer;
const defaultImage = base64DataURLToArrayBuffer(
const base64Regex =
const htmlOpts = {
    img: {
        Module: ImageModule,
        getValue: (el) => {
            const src = el.attribs.src;
            return new Promise(function (resolve) {
                // You should handle any errors here, if the promise rejects,
                // the rendering will fail with that error.
                // This is to continue to handle base64 images
                if (base64Regex.test(src)) {

                let parsedUrl;
                try {
                    parsedUrl = url.parse(src);
                } catch (e) {

                let client;
                if (parsedUrl.protocol === "https:") {
                    client = https;
                if (parsedUrl.protocol === "http:") {
                    client = http;
                if (!client) {

                    .get(parsedUrl, function (res) {
                        const data = [];

                        res.on("error", function (err) {
                                "Error during HTTP request",

                        res.on("data", function (chunk) {
                        }).on("end", function () {
                    .on("error", () => {

const content = fs.readFileSync("demo_template.docx");
const zip = new PizZip(content);
const doc = new DocxTemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],
    html: '<img width="30" height="30" src=""/>',
}).then(function () {
    const buffer = doc.getZip().generate({
        compression: "DEFLATE",
        type: "nodebuffer",
    fs.writeFileSync("demo_generated.docx", buffer);

How are pixels converted to word ?

The dpi option will allow you to convert a pixel into one inch.

By default, the dpi is set to 75, which means that 75px will be converted to 1 inch.

In previous versions (3.31.x and earlier), the deviceWidth and getDxaWidth existed, but they now are ignored in favor of the dpi option.

Customize docx-styles with classes

For block elements (p, h1,h2,h3,h4,h5,h6, ul, ol, and table), it is now possible to customize the docxstyle that is used depending on the html class of that element.

const htmlOpts = {
    elementCustomizer: function (element) {
        if (
            element.classNames.indexOf("my-heading-class") !==
                -1 &&
   === "p"
        ) {
            return { pStyle: "Heading" };
        // element.part.value will be the string "html1" if the tag used is {~~html1}
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],

The following HTML :

<p class="my-heading-class">Paragraph - heading</p>
<p>Normal paragraph</p>

will have the second paragraph rendered by using the Heading type.

Of course, you can use any docx style that you have defined in your docx template.

CSS Selectors

It is also possible to add CSS style with CSS selectors.

For example, if you want to change the font size with the CSS selector : h4, th p.important

const htmlOpts = {
    elementCustomizer(element) {
        if (element.matches("h4, th p.important")) {
            return {
                // htmlStyle must be valid CSS style
                htmlStyle: "font-size: 30px;",
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],

You can use following selectors currently :

SelectorExampleExample description
.class.introElements with class="intro"
#id#firstnameElement with id="firstname"
**All elements
elementp<p> elements
element, elementdiv, pAll <div> elements and all <p> elements
element elementdiv p<p> elements inside <div> elements
element > elementdiv > p<p> elements where the direct parent is a <div> element
element + elementdiv + p<p> elements that are placed immediately after <div> elements
[attribute][target]Elements with a target attribute
[attribute=value][target=_blank]Elements with target="_blank"

Customize bullets

It is possible to customize bullets with the elementCustomizer API

For example, you can write :

const htmlOpts = {
    elementCustomizer(element) {
        if (element.matches("ul")) {
            return {
                bullets: ["·", "-", "+"],
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts);],

It is also possible to customize the color, font and text with the elementCustomizer API :

const htmlOpts = {
    elementCustomizer(element) {
        if (element.matches("ul")) {
            return {
                bullets: [
                        text: " ",
                        font: "Wingdings",
                        color: "FF0000",
                        text: "-",
                        color: "00FF00",
                        text: "+",
                        size: 30,
                        color: "0000FF",
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],


For tables, there is no difference between table-layout:fixed and table-layout:auto.

Also, unlike the auto algorithm, the width of the column does not depend on the content of the table, but just on the width applied in the CSS style.

This means that if you want to have columns of different sizes in your generated document, you should specify the width in the first column on all tr elements.

Adding page breaks

It is possible to use the break-after: page or break-before: page styles.

Here is an example :

const htmlOpts = {
    styleSheet: `
        .pba { break-after: page; }
        .pbb { break-before: page; }
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],
    html: `<p>Hello</p>
           <p class="pba">Hi</p>
           <p class="pba">Hello</p>
           <p class="pbb">Good bye</p>

This will put a pagebreak after "Hi", after "Hello", and before "Good bye".

Add links using angular parser (from label + url)

It is possible to include links using one simple tag using a label and url data, like this.

In your template :

Header 1

{~~url | link:label}

Install following modules :

npm install --save lodash he angular-expressions

In your code, use the angular-parser and define a link filter.

const he = require("he");
const expressionParser = require("docxtemplater/expressions.js"); = function (url, label) {
    // This condition should be used to make sure that if your url is
    // undefined, your output will be undefined as well and will not
    // throw an error
    if (!url) {
        return url;
    return `<a href="${he.decode(url)}">${he.decode(label)}</a>`;
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule()],
    parser: expressionParser,

Unsupported properties

Here is a list of properties that cannot be supported, and I explain a bit why :

  • display: inline-block; or other "display" properties : In Word, everything is just simply a paragraph, or a table or an image (or some other things such as graphs, smartarts, …). And all these elements always behave like block elements. They can be positioned relatively, but inline-block, flex, grid, do not have any translation in the docx format.
  • position: absolute; or position: fixed properties : There is no translation of this property into the docx format that would render anything near this.
  • width/height on div elements : div's do not exist in the docx format as well, only paragraphs, tables, and images, and putting constraints on the width and height is not feasible except for tables and table cells.

Error : Unexpected token in htmlparser2

You might get the following error :

Module parse failed: Unexpected token (59:9)
You may need an appropriate loader to handle this file type, currently no
loaders are configured to process this file. See

Since htmlparser2 version 8.x, the package.json of htmlparser2 defines multiple exports fields :

Webpack will by default use the "module" entry of the package.json :

This means that it will load the file from "lib/esm/index.js".

I think that in your webpack configuration, you need to have the appropriate loader to be able to parse the "export" statement (and other ESM specific syntax)

You most probably currently have something like this in your webpack.config.js :

loaders: [{
    test: /\.js$/,
    loader: 'babel',
    exclude: /node_modules/,
    query: {
        presets: ['es2015', 'stage-0']

Instead you should rather use the include like this :

loaders: [{
    test: /\.js$/,
    loader: 'babel',
    include: [
        path.join(__dirname, "./app") // assuming that your config and app are in the same folder.
    query: {
        presets: ['es2015', 'stage-0']

I've inspired this answer from this webpack issue.



Bugfix to avoid adding styles with w:default="1".


Fix getSize function to call it with 4 parameters instead of one.


Add support for <span style="white-space:pre">Hello Foo</span>


Bugfix of duplicate decoding of string.

When passing following data :

const html = "<p>&amp;lt;</p>";
doc.render({ html });

The following would be shown in the template <, but this should instead show &lt;.


Remove deviceWidth option.

If you were not using the deviceWidth option or the getDxaWidth, then this change won't affect you.

Instead, you should now use the dpi option.

The default deviceWidth was previously : 470.10416666666663

The now default dpi is now 75.

If you were previously setting the deviceWidth to 1000, than, to calculate, the dpi, you have to use the formula : dpi = deviceWidth / 470.10416666666663 * 75.

For example, here are the deviceWidth to dpi mapping

deviceWidth = 1000 => dpi = 159.53
deviceWidth = 750 => dpi = 119.65
deviceWidth = 500 => dpi = 79.76


Allow to set the size of checkboxes using following style :

    html: `<input type="checkbox" style="height: 7px; width: 7px;" />`,


Keep existing text boxes that are contained in paragraphs that contain an {~~html} tag.

Previously such templates would fail with the following error :

TypeError: Cannot read properties of undefined (reading 'parts')

This also means that in that particular case, the paragraph will be kept if the HTML data value is empty.


Avoid possible issue of "Maximum call stack size exceeded"


Simplify internal generation of lists.


Improve support for nested lists together with divs.

Even li>div>div>ol should work correctly now.

    testing list
            <div>first level</div>
                            <div>second level</div>
                                        <div>third level</div>


Improve support for setting tableStyle of a table.

When using the tableStyle option, now the colors of the used table will be correctly copied from word/styles.xml, taking into account the "firstRow", "lastRow", "firstCol", …


Avoid corruption when having a <table> tag inside a Word table that results in a width of 0 in async mode, which corrupts the document


Fix error : Raw tag not in paragraph error when using a loop that contains some inline HTML tag.

Previously the following would fail (on some occasions when the tag was written in the same run, <w:r>) :

{#html}The html is {~html}{/}


Bugfix to take into account img { display: block; margin:auto; } when using docxtemplater in async mode.


Avoid corruption when using img { display: block; margin:auto; } with images inside <li> elements.

See :

Now, <img> tags that are inside <li> tags will always be rendered as "inline-block" elements.


Bugfix to stop adding empty paragraphs after tables.

Please update the main docxtemplater library to 3.29.4 to fix this problem correctly


Do not add an empty paragraph after each <table>

Make it possible to specify table { margin-bottom: 20px; } to add a margin after tables.


Bugfix to make it possible to have a Promise returned in the getSize function.

Previously the message shown was :

"Uncaught (in promise) Error: Size for image is not valid (it should be an
array of two numbers, such as [ 1024, 1024 ])


Improve typescript definitions


Bugfix corruption when having one column with fixed width, and 3 columns with auto width.


Bugfix to use the synonym of "Heading1" style if the synonym exists.


Bugfix when using a dotx template and using a table.

The table would appear as zero-width, which would cause a corruption.

Now the template is handled correctly.


Bugfix to take into account border="0" property in table, like this :

<table border="0">
        <td>Table with no borders</td>


Make package size smaller


Bugfix corrupt document when adding HTML link inside header


Avoid using styles that reference non-existing styles


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.


Make module compatible with docxtemplater@3.27.0. Please make sure to update docxtemplater to 3.27.0 at the same time you update this module


  • Use WidthCollector for each parsed file (makes module compatible with image module 3.10.0)


  • Add support for <table align="right">. It is also possible to use <table style="margin-left: auto"> to align a table to the right.

  • Add support for bordercolor attribute on <table bordercolor="#bbb">.

  • Add support for cellpadding attribute on <table cellpadding="5">.


Make img.getValue optional, even when running docxtemplater in async mode.


Update typing to allow ArrayBuffer or Promiseon getValue function


Update typing files to add types for using together with image module, with

const htmlOpts = {
    ignoreUnknownTags: true,
    img: {
        Module: ImageModule,
        getValue: (el) => {
            return Promise.resolve(Buffer.from("hhh"));
        getSize: function (data) {
            return [100, 100];
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],


Add internal clone method (to use image tags with the Subtemplate.Segment module)


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/html-module.js The .min.js file is also created now.


Add support for <ol start="3"><li>An item</li></ol> to start the list items at a different position, to render :

3. An item
4. An other item


Add support for images without src when using following CSS :

img {
    display: block;
    margin: auto;

Previously this would result in a corrupt document


Add support for setting the prefix to an empty string (to be able to replace normal tags by inline HTML).

To change the prefix for block tags, one will have to change the prefix like this :

For example to use {!!html} for block html, and {tag} for inline html :

function getHTMLModule() {
    const htmlModule = new HTMLModule();
    htmlModule.prefix = "";
    htmlModule.blockPrefix = "!!";
    return htmlModule;
const doc = new Docxtemplater(zip, {
    modules: [getHTMLModule()],


Add support for centering images in the output word document.

To use it, you need to add following styleSheet :

const htmlOpts = {
    styleSheet: `
        img {
            display: block;
const doc = new Docxtemplater(zip, {
    modules: [new HtmlModule(htmlOpts)],


Add typescript definitions for public API


Improve support for columns width, so that tables inside columns which are of unequal width will render correctly.

For example, if you have a document with two columns, one of width of 2/3 of the document, and an other one of 1/3 of the document width, a table with width of 100% will be calculated correctly.

Previously, the width would be in this case always splitted equally, so you would have a smaller table on the column with 2/3 of the space.


Move webpack from dependency to devDependency (which triggered an error during installation on node version 10)


Bugfix issue when using "text-align: right", on a table cell, where the {~~html} tag was explicitly left-aligned.

Now, the text-alignment from the HTML style will take precedence and show the text aligned correctly.


Add support for table-layout: fixed; CSS property (which translates to <w:tblLayout w:type="fixed"/>)


Add support to customize pStyle for <pre> tags, for example

const htmlOpts = {};
htmlOpts.elementCustomizer = function (element) {
    if (element.classNames.indexOf("ql-syntax") !== -1 && === "pre) {
        return { pStyle: "Code" }
const doc = new Docxtemplater(zip, {
    modules: [new HtmlModule(htmlOpts)],
    html: `<pre>Hello from
        pre tag</pre>`


Add support for repeatHeaderRow and cantSplit on table row elements with elementCustomizer

For example, you can now do :

const htmlOpts = {};
htmlOpts.elementCustomizer = function (element) {
    if (element.matches("tr.header")) {
        return {
            cantSplit: true,
            repeatHeaderRow: true,
    if (element.matches("tr")) {
        return {
            cantSplit: true,
const doc = new Docxtemplater(zip, {
    modules: [new HtmlModule(htmlOpts)],
    html: `
        <tr class="header">
        <tr class="header">
        <tr><td>Some Text</td><td>Other Text</td></tr>
        <tr><td>Some Text</td><td>Other Text</td></tr>

And this will set the two header table rows to be repeated across each page when the table overflows. The cantSplit property can also be used to avoid the table row to be splitted between two pages.


Add support for <ol type="I"> to show ordered lists with uppercase roman numbers.

Here are the possible types :

  • type="1" The list items will be numbered with numbers (default)
  • type="A" The list items will be numbered with uppercase letters
  • type="a" The list items will be numbered with lowercase letters
  • type="I" The list items will be numbered with uppercase roman numbers
  • type="i" The list items will be numbered with lowercase roman numbers

Add support for style list-style-type and list-style, to use CSS to customize numbering.

For example :

const htmlOpts = {
    styleSheet: `
    ol {
        list-style-type: upper-alpha;
    ol.roman {
        list-style: upper-roman;
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],

The list of possible values are : decimal-leading-zero, decimal, lower-alpha, lower-latin, upper-alpha, upper-latin, lower-roman, upper-roman


Add support for background-color on table element (previously it could only be set on tr or td)


Add support to customize bullet colors and font-family using elementCustomizer


Add support to customize li pStyle using elementCustomizer


To use this version with the image-module, you need to use the image-module version 3.8.4

Allow to retrieve containerWidth in getSize function when using <img> tags.

For example :

const options = {
    img: {
        Module: imageModule,
        getSize({ element, src, part }) {
            return [
                part.containerWidth || 100,
                part.containerWidth || 100,

This allows to for example show all images as being the size of the container (most commonly, the size of the page, except when the HTML tag is inside a table).


Allow to have comments in stylesheets


Bugfix to take into account "border:none" on <table> elements


Correctly keep <w:rtl> tag in order to allow to insert "right-to-left" languages such as Hebrew.


Add support for <style> tag inside HTML tags


Disallow to pass something other than a string to the stylesheet option (because this option only allows to pass a given global stylesheet)


Bugfix, when having text surrounding the HTML inline tag, such as in :

Hello {~name}, how are you ?

The HTML module would sometimes misplace the replacement of {~name} and put it at the end of the paragraph.

Now, the module correctly puts the replacement at the correct position.


Use w:lineRule="exact" when using CSS line-height


Add support for line-height attribute.


Improvements for cell widths. Now, when you declare only the widths of td (without defining the width of the table itself), the cell widths will be correct (the table width will be the sum of all cell widths).

For example : this will work :

const htmlOpts = {
    styleSheet: `
td {
    width: 50px;
const doc = new Docxtemplater(zip, {
    modules: [new HTMLModule(htmlOpts)],

Previously, this would result in having a default table width of 450px, and scaling of the cell widths.


Bugfix when having <br> in "implicit paragraph", for example in :

<br />
<br />

In previous versions, this would render two empty paragraphs between each title, now it correctly renders only one


Avoid importing unused styles, such as :

"Heading Car" "Heading 1 Car" "Heading 2 Car" "Citation Car"

Those styles are now imported only if the corresponding style does not exist in the templated document.


Add support for :

  • <table> that contains some empty <tr> elements (it would generate a corrupt document)
  • <input type="text">
  • <form> tag (no specific style currently)
  • <textarea> tag (no specific style currently)
  • <button> tag (no specific style currently)
  • <label> tag (no specific style currently)


Fix issue with css module :

Module not found: Error: Can't resolve 'fs' in '[...]\node_modules\css\lib\stringify'

Now, the module requires only the part that it uses, which removes this error.


Add support for "dotted" border-style.

Add support for border-style with multiple values (one to four values)


Bugfix to ignore <br> at the end of block elements.


Bugfix support for border styles, such as border: 1px dashed black;

List of handled styles : solid, dashed, double, outset, none, inset


Add third argument to styleTransformer() containing styleIds of the current document.


Bugfix to render space in inline HTML tag when using : <b>Foo</b> <i>Bar</i>


Fix error when using <img> tag without any src. The error message was TypeError: Cannot read property 'replace' of undefined at base64DataURLToArrayBuffer. Now, those images are ignored but do not fail with an error.


Improve table border support :

  • Add support for border-width property on border

  • Add support to change default for table borders with elementCustomizer, for example :

const options = {
    elementCustomizer({ name }) {
        if (name === "table") {
            return {
                tblStyle: "TableauNormal",
                defaultBorder: null,

This makes it possible to use border style defined in the Word style.


Add support for <ins> and <del> tags (which will render underline and striked text)


Do not produce corrupt output when having either :

  • Tr element without any child : <table><tr></tr></table>

  • Table element without any child : <table></table>

Instead, the table will not be shown at all.


Correctly ignore width='0' on <table> element.


Do not render newline when it is at the end of a <li> element, for example, in :

    <li>Hello<br /></li>
    <li>Hello<br /></li>


Render text that is inside an <ul> even if it is not in a ul.

In previous versions, the tag <ul>Hello</ul> would produce an empty paragraph. Now it will render a paragraph with the word "Hello".


Add support for "padding" property.

Previously, only "padding-left", "padding-right", "padding-top" and "padding-top" were working, but not she shorthand padding: 0 property for example.

For table cell margins, support all common units (not just px unit).


Make it possible to specify margin: 0 (or margin-left: 0) on table element. (It was ignored in previous versions)


Return an empty paragraph when using <p><br></p> instead of having a two-line paragraph


  • Bugfix Cannot read property 'getElementsByTagName' of undefined at addRelationship (es6/relation-utils.js:25:32) when using docx file saved from the online office 365 web app.

  • Add styleIds to elementCustomizer API to be able to know which styles are defined in the document when changing pStyle.


  • Remove tableRatio option (you should use deviceWidth instead)

  • Add support for "cm", "in", "mm", "pc", "pt" for all measurements

  • Bugfix do not produce a corrupt document when having escape codes such as an "escape character" (String.fromCharCode(27)). These characters are now ignored, like what a real browser does.


Add support for pt unit in font-size, for example : font-size: 15pt

The pt unit is for now not supported on all measures however.


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


Add element.parsedStyle which contains the parsed CSS style for usage in getSize of image module


Add support for text-indent to indent first line of a paragraph.


Bugfix : Do not fail if using more list levels than are defined in pStyle.

For example :

const htmlOpts = {
    styleTransformer: (tags, docStyles) => { = ["bulletLevel1"]; = false;
        return tags;
const doc = new Docxtemplater(zip, {modules: [new HtmlModule(htmlOpts)]})

will use bulletLevel1 for each level of bullets.

Previously, this was failing with the following error code :

TypeError: Cannot read property 'oneOf' of undefined


Bugfix : Previously, when having text just before an inline HTML tag, like in :


The text Hello was removed from the output.

This is no longer the case, the text on the left and on the right of the inline tag will be kept.


If using ignoreUnknownTags to true, hide images instead of throwing an error.


Add support for caption on images when using the image module version 3.7.0 or above.


The runProperties (w:rPr) used where the first encountered, instead of using the one inside the run itself (w:r).


For table tag, when the {~~htmlTag} is inside a multi-column session, the width:"100%" will use the width of one column instead of the width of one page.


Add support for margin-left on paragraphs


Add support for font-family in CSS


Add support for break-after: page and break-before: page in CSS


Add support for <pre> tag

Make it possible to have width: 100% for images inside tables

Fix the calculation of width for images so that a table with a width of 200px shows the same width as an image with width of 200px. Before this release, the images were smaller than expected.


Keep paragraph style including indents and alignment


Add support for pt values on table width


Add support for margin: 0 (without any unit)


Add support for colspan + rowspan on the same cell.

Multiple improvements for rowspan


Add support for Right-To-Left support with w:bidi tag.

Add support for margin-top and margin-bottom on li tags


Bugfix corrupted document when using margin-top or margin-bottom


Add support for margin-top and margin-bottom on paragraphs


Bugfix spacing in li :

<li><em>Lorem ipsum dolor si amet</em> <strong>Test</strong></li>

The space will now be correctly rendered


Bugfix : support vertical-align: middle; for td


Add initial support for rowspan on table td


Bugfix of propagation of style to all paragraphs.

For example, when having :

    <p style="text-align:center">Centered</p>

The first paragraph was centered even if it should not.


Bugfix to avoid Cannot read property 'concat' of undefined" when defining styles on some elements (such as th).


Always generate output with w:sz as integer (instead of float) by using Math.round


Add support for td { width: 20% } in CSS

Bugfix issue of width of all cols being smaller than width of whole table


Add support for :

  • :first-child, :last-child, :nth-child(3) selectors
  • border-left, border-top, border-right and border-bottom on td and th for tables
  • text-align:center on th/td
  • border-style double property


Bugfix for "Cannot read property 'getAttribute' of undefined" when having styles without names.


Bugfix [object Object] shown when using async mode (resolveData) with null value


Bugfix corrupt document when having empty w:sdtContent


Add support for async image generation


Keep fontFamily if set in run properties


Do not corrupt document if having empty value in block html inside table cell


Do not fail if they are no sections at all in the document (return a default size).


Bugfix corrupt document when using table colspan with just one row.


  • Add support for centered tables with margin: 0 auto;


Inherit paragraph properties inside tables.


  • The table color properties were "leaking" from one cell to the other, resulting in wrong colors being used sometimes. This is now fixed


  • Improve list support when ul is a direct child of ol or or is a direct child of ul.

  • Add the style (run properties) of the {~~htmlTag} to bullet points so that the bullet points have the same size as the text


  • Add support for font-weight:bold of font-weight:700


  • Add support for styleSheet option in module constructor


  • Add support for margin-left on ul and ol


  • Better support for ul and ol : when using ols inside uls, if the TextBody style did not exist, the ul and ol style were missing bullets.

  • Add way to customize bullets in the elementCustomizer API


Update html-parser require calls to work well with Rollup


Improve table support (background && background-color, color, font-size.

Do not duplicate runProps anymore


Add support for inline and block <code> tags


Update to support the new image module v3.4.2


Update to support new image module with <svgs> (3.4.1 of the image-module)


Add support for <a name="mark"></a> to generate docx bookmarks


Add support for <a href="#mark">Go to mark</a> and <p id="mark">Mark</p> by using docx bookmarks


Links with no content are now hidden from the generated document (ignored)


Add two additional options for determining the meaning of 1 pixel.

The deviceWidth option explicitly permits to say that you want to have a window of for example 1200 pixels.

The getDxaWidth option to select how many dxas (20th of a point, or 1440 of an inch) your page is.

With these two options, docxtemplater can then accordingly convert any pixel value to a coherent size in your word document.


Add support for setting properties on multiple levels of divs/blockquotes or any block element.

For example :

<div style="text-align: justify;">
        Sit aliquid vitae non magni ex Eius saepe molestias
        minima non tempore amet! Accusamus corrupti at ipsa
        necessitatibus consequatur. Corporis autem debitis
        reiciendis illo modi, inventore. Delectus magni sint


Add support for images inside link and inside lists, for example :



Add part argument to getSize


  • Add support for : text-align: justify

  • Add support for : bgcolor attribute on td and tr


  • Add support for : padding-top,padding-bottom,padding-left,padding-right on td

  • Add support for valign attribute on td

  • Add support for color in more CSS formats for background-color, color, border-color, for example : <span style='color: white;background-color: hsl(120, 100%, 50%); '>color output</span> will now work.

  • Make it possible to use text-align inside td


Add support for :

  • vertical-align style on td
  • background-color style on tr
  • border-color on td


Make it possible to customize pStyle for list items, for example :

const ulpStyles = ["ListBullet", "ListBullet2", "ListBullet3"];
options.elementCustomizer = function ({ name, listLevel }) {
    if (name === "ul") {
        return {
            pStyle: ulpStyles[listLevel],
            useNumPr: false,

listLevel will be 0, 1, 2 depending on the nested level of the item in the HTML.


Do not apply elementCustomizer on implicit paragraphs.

For example, if you had in your html :


and wrote :

const opts = {
    // ...,
    elementCustomizer(element) {
        if (element.matches("td")) {
            return {
                pStyle: "TextBody",
        if (element.matches("p")) {
            return {
                pStyle: "Heading",

Then, before this version, the text "Lorem" would use the "Heading" style.

In this new version the implicit paragraph <p>Lorem</p> would not trigger a call to elementCustomizer at all, thus using "TextBody", which is the correct style to apply !


Make it possible to style implicit paragraphs in td by setting a pStyle on the td element from elementCustomizer.

  • Fix bug of pStyle not kept in certain cases.


  • Add support to set td width with style in px

The style property takes precendence over the style attribute, for example :

<td width="100" style="width: 400px" align="center">John</td>

will resolve to a width of 400px.


Add ignoreCssErrors to ignore CSS parse errors.


  • Add new selector API that makes it possible to style elements with CSS like selectors , for example :

    const opts = {
        // ...,
        elementCustomizer(element) {
            if (
                    "th h3.p1, tr>th>h3.p3, tr>h3.nomatch"
            ) {
                return {
                    htmlStyle: "background-color: #ff0000;",
  • Add way to remove all table borders by specifying :

    For example

    <table style="border: none;">
  • Bugfix add possibility to style <a> element (link)


  • Update browser build to use XMLSerializer instead of xmldom

  • Use requiredAPIVersion


  • Fix browser build failing Nodes of type '#document' may not be inserted inside nodes of type ...


  • Fix browser build "TypeError: Argument 1 of XMLSerializer.serializeToString does not implement interface Node."


  • Support elementCustomizer even when having deeply nested paragraphs, for example with <div><p>Hello</p></div>


Add support for :

  • align attribute on table cell

  • enhance colspan support when widths are not all fixed

  • table width as percentage


Add support for :

  • Background-color in tables (in css format)

  • Better use width in tables (which now generates colgrid and gridspan)

  • Add support for align="center"

  • Background-color in span (in css format)


  • Add {part} argument to elementCustomizer


  • Move docxtemplater from devDependencies to dependencies

Explanation : On some versions of npm (notably 5.8.0), when having a package containing docxtemplater-html-module, the installation will generate a tree of node_modules that puts the module on a level where it has no access to docxtemplater. By explicitly asking it as a dependency, this issue is avoided.


  • Drop paragraphCustomizer api (which was added in 3.8.4), for a more generic elementCustomizer API.


Make it possible to customize docxstyles depending on classnames.


  • Make module compatible with docxtemplater version 3.5 and below.

Explanation : Recently, the scopemananger API (internal API) has changed, this new version of the html module makes the module work with both versions newer than 3.6 and older than 3.6 of docxtemplater.


Add support for svg tag (needs the image module too) (this format is only readable on newer Word version : Microsoft Word, PowerPoint, Outlook, and Excel 2016 on Windows, Mac, Android and Windows Mobile).


Add meta context argument to custom parser with information about the tag for each types of tags


  • Use default paragraph style instead of textbody for paragraphs


  • Fix issue with style that were overriden if the styles had the same name


  • Add styles only when using an HTML tag


  • Add way to change the size of paddingLeft with sizeConverters


  • Add support for padding-left : <p style="padding-left:15px">Hello</span>


  • Add support for font-size : <span style="font-size: 15px">Hello</span>


  • Add support for more image types in img tag : GIF, JPEG, BMP, PNG work now


  • Add support for blockquote tags


  • Correctly handle &#58 in style attributes (parsed as :).
  • Fail with clear error message if style attribute cannot be parsed


Add support for <img> if using imagemodule.


Throw explicit error when using pptx instead of docx


Fix bug introduced in 3.5.5 : When using <li> elements, all child tags are now correctly rendered (before, only the first child was rendered).


When using <a>Link</a> without href, set the Target to "" instead of "undefined"


Handle multiple occurences of noBreakHyphen in same tag


Handle noBreakHyphen


Improve whitespace support.


  • Fix rendering of space between tags for inline tags too {~html}, for example :
<p><b>Foo</b> <u>Bar</u></p>

will now correctly render "Foo Bar" instead of "Foobar"


  • Fix rendering of space between tags for block tags, eg {~~html}, for example :
<p><b>Foo</b> <u>Bar</u></p>

will now correctly render "Foo Bar" instead of "Foobar"


  • Add possibility to customize styles for nested <ul>,

eg :

this.options.styleTransformer = function (tags) { = [
    ]; = false;
    return tags;

This will set the "ListBullet" for level 0 of <ul>, "ListBullet2" for level 1 and so on.


  • Add possibility to customize styles for BulletList with styleTransformer


  • Add option styleTransformer to customize styles.
  • Do not set <w:spacing w:before="0" w:after="0"/> for each paragraph, but use the one that is set in the paragraph containing the {~~blockTag}, if present.

This release needs version 3.1.11 of docxtemplater.


Bugfix issue with styles of TextBody or BodyText being wrongly changed.


Bugfix issue with bullet lists no more appearing


  • Fix issue with duplicate list content when using <ul><li><em>Test</em> after</li></ul>
  • All html escapes are now currently handled, including &#xA0, &and;, and all html handled escapes


  • Add support for text-align:center and text-align:right
  • Add correct styles for h5 and h6


  • Handle escapes such as &quot; &amp; &#x27; &gt; &lt;


  • Add possibility to ignore unknown tags with an option
  • Add support for <sub> and <sup>


Add support for style="text-decoration: underline"


Handle nested ul/li:

            <li>Nested 1</li>
            <li>Nested 2</li>


Multiple fixes for tables :

Add support for tables that have :

  • no <tbody>, and directly <tr>
  • <thead> or <tfoot>
  • <th> instead of <td>

Also, allow td to be empty, for example :


Fixes links containing dom children to be shown as "undefined", for example :

<a href="">Foobar <span>Foo</span></a>


Make it possible to add paragraphs nested inside paragraphs, for example :






Fix issues with &amp; and others not getting decoded


Add support for background-color on p element. It uses the fill property of word, which sets the background-color for a full paragraph.


Add auto wrapping of inline elements in block-elements, so that <span>Foobar</span> is also valid in {~~blockElement}. Also, this makes it possible to use <td>Foobar</td> (the wrapping of the <p> is done for you).


Add support for inline style background-color:blue


Fixes following error in version 3.1.2 : "Cannot find module '../static/styles.json'"

3.1.2 [WIPED](Please use 3.1.3)

Bugfix when using multiple <ol>, the numbering is reset correctly for each <ol>


Bugfixes when using elements other than <p> inside a <td> (eg now <ul> works)


Bugfixes when using :

  • table inside table
  • multiple lists (<ul>, <li>)
  • multiple links to same Target


Fix bug when using tags inside lists, for example, <ul><li><i>Foo</i></li></ul> now works as expected


Update rendering of <ol> to use the default symbol.


Do not change style of Title, Heading1 - Heading6 of current document


Add support for <input type="checkbox"> and <input type="checkbox" checked>


Fix right borders for tables


Fix corrupted documents with some templates


Add support for <a href="URL">LinkText</a>


Add support for inline style color:#ef0000


Keep word-run style for inline replacement. For example if, the text that the {~html} tag is written in is red, it will also be the base style for the generated elements of the html tag.


Keep existing style. For example, if the html is : <p>Foobar</p>, the text should be styled the same as the rest of the document.


Add support for ol,ul and li tags


Update demo and readme


Initial release

Talk with sales