htmltemplatesmustache

Mustache curly braces being moved out of table element within <template> HTML


The HTML5 template element seems to mangle Mustache curly braces in the HTML output, particularly within a table:

<template id="test">
    <table>
      {{#foo}}
        <tr><td>{{.}}</td></tr>
      {{/foo}}
    </table>
</template>

<script>
    const html = document.getElementById("test").innerHTML;
</script>

The inner HTML shows this:

{{#foo}}{{/foo}}<table><tr><td>{{.}}</td></tr></table>

However, if instead of a template we use a script element, the HTML is not mangled:

<script id="test" type="text/html">
    <table>
      {{#foo}}
        <tr><td>{{.}}</td></tr>
      {{/foo}}
    </table>
</script>

The inner HTML is correct, and can be used by Mustache:

<table>{{#foo}}<tr><td>{{.}}</td></tr>{{/foo}}</table>

Why is it that this happens with template? Is there a way to somehow disable this behavior? Otherwise, apparently, it's not a good idea to use it with a template system like Mustache?


Solution

  • <template> is specifically meant for use with Web Components, which has its own templating mechanism that is integrated in the web standards. The HTML inside a <template> element should be considered "live" and must be well-formed, so you cannot just insert arbitrary text inside <table>...</table> without also wrapping it in <td>...</td>.

    While a <script type="not-javascript"> may feel old-fashioned and perhaps a bit makeshift, it is still the only correct way to embed arbitrary template code in an HTML document.

    Alternatively, you can save your template in a separate file and import it in your JavaScript modules with the help of a bundling tool and a suitable plugin. For example, if you were to bundle your JavaScript code using Rollup and use Wontache to render your Mustache templates, you could use rollup-plugin-wontache and structure your code as follows:

    template.mustache

    <table>
      {{#foo}}
        <tr><td>{{.}}</td></tr>
      {{/foo}}
    </table>
    

    script.js

    import template from './template.mustache';
    
    var htmlCode = template({foo: ['item 1', 'item 2']});
    

    There are similar plugins for other combinations of bundling tools and Mustache rendering engines.