Temme (or Emmet in reverse) is to javascript what Emmet is to HTML and CSS, with no doubts, Emmet saved us from the headache of working with HTML and CSS, and now, it's about time Javascript had the same quirk too.
Temme works with javascript objects instead of plain text: give it a hierarchy object describing an HTML skeleton and an element to host it, and it builds the DOM tree for you. The library is dependency-light, fully typed and tree-shakeable.
pnpm add temmejsnpm install temmejsyarn add temmejsThe package is also published to GitHub Packages as @eoussama/temmejs. More installation options are covered in the wiki.
| File | Format | Use it for |
|---|---|---|
dist/temme.mjs |
ES module | Bundlers and Node.js import (with temme.d.mts types) |
dist/temme.cjs |
CommonJS | Node.js require (with temme.d.cts types) |
dist/temme.browser.mjs |
ES module (min) | <script type="module"> straight from a CDN, no dependencies |
dist/temme.umd.js |
UMD (min) | AMD, CommonJS or the Temme global; the CDN default |
dist/temme.iife.js |
IIFE (min) | A classic <script> tag exposing the Temme global |
declare function parse(
hierarchy: object,
target: HTMLElement,
endCallback?: (hierarchy: Hierarchy) => void | Promise<void>,
nodeCallback?: (temmeId: string, hierarchy: Hierarchy) => void,
): Hierarchy;
declare function validate(hierarchy: object): { valid: boolean; error: unknown };parsevalidates the hierarchy, completes it in place (defaults, inherited values, temmeIds), renders it intotargetand returns it. Parsing the returned object again renders the same tree.validateruns every checkparseruns, on a copy, without rendering anything.- Invalid input throws one of the exported error classes, all extending
TemmyError, with a message prefixed by[Temme]:. - The
HierarchyInputtype describes valid hierarchy objects, for type-checked hierarchies in TypeScript.
<!-- The element we're going to append the HTML skeleton to. -->
<div id="target"></div>
<!-- Including Temme JS, which exposes the `Temme` global. -->
<script src="https://cdn.jsdelivr.net/npm/temmejs/dist/temme.iife.js"></script>
<!-- Putting Temme to do its thing. -->
<script>
Temme.parse(
{
classes: ["card", "card-dark"],
templates: [{ ref: "paragraph", classes: ["text"] }],
childNodes: [
{
name: "div",
classes: ["card-header"],
childNodes: [
{
name: "h2",
classes: ["title", "bold"],
attributes: { contenteditable: true },
content: { value: "Card header" },
},
],
},
{
name: "div",
classes: ["card-body"],
dataset: { source: "example.com", id: 536 },
childNodes: [
{
name: "p",
content: { value: "Plain text, <b>escaped</b>." },
from: { ref: "paragraph" },
},
{
name: "p",
content: { type: "html", value: "Some <b>bold</b> HTML." },
from: { ref: "paragraph" },
},
],
},
],
},
document.getElementById("target"),
);
</script>Simply that, giving Temme a target element and a skeleton object, it will render the following.
<div id="target" class="card card-dark">
<div class="card-header">
<h2 class="bold title" contenteditable="true">Card header</h2>
</div>
<div class="card-body" data-source="example.com" data-id="536">
<p class="text">Plain text, <b>escaped</b>.</p>
<p class="text">Some <b>bold</b> HTML.</p>
</div>
</div>With a <script type="module">, import the self-contained browser build instead:
import { parse } from "https://cdn.jsdelivr.net/npm/temmejs/dist/temme.browser.mjs";// ESM
import { parse, validate } from "temmejs";// CommonJS
const { parse, validate } = require("temmejs");Temme needs a DOM to render into: the browser's, or one from a library such as happy-dom or jsdom in Node.js.
const target = document.createElement("div");
try {
parse({ classes: ["red"], childNodes: [{ name: "p", content: { value: "Hello" } }] }, target);
}
catch (error) {
console.error(error.name, error.message);
}
validate({ bogus: true });
// { valid: false, error: InvalidOptionNameError: “bogus” is not a valid option }More on how to use Temme can be found at the documentation web page and even more in-depth in the wiki, including the options and inheritance.
Requires Node.js 24 or later and pnpm 12 (npm and yarn are refused).
pnpm install
pnpm check| Command | Description |
|---|---|
pnpm build |
Builds every format into dist/ with tsdown, then checks the package with publint and attw. |
pnpm dev |
Rebuilds on change. |
pnpm build:site |
Assembles the documentation site (docs/ and the browser build) into _site/. |
pnpm typecheck |
Type checks with the TypeScript 7 native compiler. |
pnpm lint |
Lints with @eoussama/dx (pnpm lint:fix fixes). |
pnpm test |
Runs the unit and integration tests, failing below 100% coverage. |
pnpm test:smoke |
Tests the built dist/: every format, the types, tree-shaking and the package. |
pnpm test:e2e |
Tests the documentation site and the examples in Chromium with Playwright. |
pnpm test:mutation |
Runs Stryker mutation testing, failing below a 95% score. |
pnpm check |
Runs all of the above, plus pnpm audit. |
More about building and testing in the wiki.
Icon made by Freepik from Flaticon and licensed by Creative Commons BY 3.0.