HTML6 Template Engine
A lightweight, component-based server-side template engine for building fast, dynamic HTML from plain JavaScript. It's the engine powering this site's own rendering.
Timeline
Stable
Team
2 developers
Role
Co-Developer & Maintainer
Overview
HTML6 is a server-side template engine that compiles plain HTML into fast, reusable render functions. The motivation was for someone who only knows HTML and CSS to be able to write conditionals, loops, and components without ever touching JavaScript or a framework like React.
The Challenge
The goal was for HTML6 to be the fastest template engine out there, not just a workable one. The catch: tags like if/elsif/else need to see their siblings to resolve correctly, and the obvious way to handle that means walking the parsed tree more than once, exactly the kind of overhead a fastest-in-class claim can't afford.
The Solution
HTML6 compiles by walking the parsed tree exactly once, bottom-up, dispatching each node only after its children are done. The technique that makes that possible is masking and unmasking.
Tags that need sibling context, like an if/elsif/else chain or a map loop, get masked instead of resolved inline: swapped for a placeholder key in a lookup table so the walk never has to backtrack. Once that single pass finishes, unmasking swaps every placeholder back to its real content, and the result is wrapped into a native JavaScript render function.
It's just .html
Every HTML6 template is a real .html file. Not .pug, not .hbs, not a .jsx file pretending to be markup. It's HTML with a few extra attributes and {{ }} sprinkled in, so your editor, Prettier, and every linter you already have already understand it.
That's the actual differentiator, more than any single feature below. No plugin to install, no new extension for your tooling to learn, no build step standing between the file you write and the file the browser would recognize as HTML. A UI/UX designer with zero JavaScript experience can open the file and follow exactly what it's doing.
Real JavaScript, not a mini-language
Interpolations and conditionals run real JavaScript expressions against the render scope, not a simplified template language that only looks similar:
<h1>{{title}}</h1>
<div if="user.loggedIn">Welcome back</div>
<div elsif="user.pending">Pending approval</div>
<div else>Please log in</div>
If it's valid JavaScript, it's valid inside {{ }} or an if. There's no mini-language to look up.
Loops with map
map loops over arrays directly on the tag, with an optional index and its own if:
<ul>
<li map="p, i of projects" if="p.title.length > 0">{{i}}: {{p.title}}</li>
</ul>
Nested loops work the same way, one map attribute per level:
<div map="group of groups">
<h2>{{group.name}}</h2>
<ul>
<li map="item of group.items">{{item}}</li>
</ul>
</div>
Pipes for safe transforms
Function calls inside {{ }} are disabled for security. |> chains transforms onto a value instead:
{{title |> upper |> truncate 20}}
{{price |> formatCurrency}}
{{date |> formatDate 'YYYY-MM-DD'}}
Pipes are just functions registered by name, so adding a new one is a few lines of JavaScript, not a change to the template language itself:
var pipes = {
upper: (x) => String(x).toUpperCase(),
truncate: (x, len) => String(x).slice(0, len)
}
html6.compile(template, { pipes })
Components, slots, and isolated props
<template is="..."> defines a component. <slot> marks where its children get inserted. Props stay isolated to that component, while everything else in the outer scope flows down automatically, without being re-declared at every level:
<template is="card" title="string">
<div class="card">
<h2>{{props.title}}</h2>
<slot></slot>
</div>
</template>
<card title="Hi {{user.name}}">
<p>Rendered from the slot.</p>
</card>
Compiles once, runs on every request
compile() takes the template and returns a render function. That's the expensive part, so it only runs once, at startup, and the result gets cached. Every request after that just calls that cached render function with fresh data.
Where it actually runs
HTML6 first shipped in production at Nobo, the workplace this all started at. It also powers Ultimate Learning, a language-learning app I actively maintain. Two real production sites, not a demo that got built once and abandoned.
Interested in this project?
I'd love to discuss the technical details, challenges faced, and lessons learned from building this project.
Get in Touch