HTML Templating Lessons
journalI used to be a staunch proponent of logicless templating. Years of conversations with folks like Till and Lucas, along with countless experiments and real-world experience, gradually led me to the following realizations:
- There are three types of markup: static boilerplate, variable parts defined once upon instantiation and dynamically-updated portions. The latter is irrelevant for server-side templating.
- Any dedicated templating language often turns out to be less than ideal, possibly even problematic – especially with regard to composable abstractions. Thus it’s generally preferable to just rely on the well-defined language you’re already using for your system anyway.
- … which is particularly feasible with JavaScript’s tagged templates. Those also provide decent ergonomics, which is an important factor.
- Generating HTML isn’t magic; it’s actually fairly straightforward.
While I hesitate to recommend the DIY approach described in that last post – in part because it currently lacks proper authoring documentation – I increasingly find myself relying on my own single-module implementation (remember that I’ve become very wary of dependencies) – especially for experiments and small prototypes. That typically looks something like this:
import { renderDocument } from "./doc.js";
import { html } from "./html.js";
let title = "Hello World";
renderDocument({
lang: "en",
title
}, html`
<h1>${title}</h1>
<form method="post"${{ action: url }}>
${textField("Name", "name")}
${textField("Description", "desc", { multiline: true })}
<button>Submit</button>
</form>
`);
function textField(caption, name, { multiline }) {
let field = multiline
? html`<input type="text"${{ name }}>`
: html`<textarea${{ name }}></textarea>`;
return html`
<label>
<b>${caption}</b>
${field}
</label>
`;
}
YMMV.