Repository navigation
Temme inheritance
Temme (Emmet in reverse) is a lightweight JavaScript library for generating and composing HTML structures from plain JavaScript objects.
Instead of writing imperative DOM manipulation code or injecting raw HTML strings, you describe your UI as a hierarchy object and let Temme turn it into real DOM nodes. The library is especially useful when you want a clean, data-driven way to create markup, reuse structure, and compose elements programmatically.
Temme currently exposes a modern named-export API:
parse(hierarchy, target, endCallback?, nodeCallback?)validate(hierarchy)
It also supports advanced composition features such as templates, references, inheritance, include/exclude ranges, and controlled child inheritance.
With Temme, building DOM trees is done by describing elements as JavaScript objects.
A hierarchy can define things like:
- element name
- id
- classes
- attributes
- dataset values
- content
- child nodes
- reusable templates
- inheritance from other nodes or templates
Once the hierarchy is defined, you pass it to parse(...) along with a target HTML element. Temme validates the structure, sanitizes it, resolves references and inheritance rules, and finally renders the resulting DOM tree into the target.
In practice, this means you can model complex HTML structures in a way that is:
- readable
- composable
- reusable
- easy to serialize as JSON
In fact, the documentation website itself is generated with Temme.
You might ask: why use this instead of plain DOM APIs or Emmet-style shorthand?
While Emmet is optimized for fast shorthand expansion, Temme is optimized for working with structured JavaScript data. That makes it a better fit for programmatic DOM generation.
Temme removes a lot of repetitive low-level DOM code such as:
- repeated
document.createElement(...) - repeated
appendChild(...) - repetitive attribute and class assignment
- manual nesting logic
For many use cases, describing content as objects is easier to read and maintain than assembling large HTML strings manually.
Temme supports reusable templates and inheritance rules, which makes it easier to share structure and styling across multiple nodes without duplicating configuration.
Because Temme works with plain object hierarchies, its structures can be serialized to and from JSON easily. This makes it useful for configuration-driven rendering and data-based UI generation workflows.
The current version includes validate(hierarchy), which lets you check whether a hierarchy is valid before rendering it.
parse(
hierarchy: object,
target: HTMLElement,
endCallback?: (hierarchy: Hierarchy) => void | Promise<void>,
nodeCallback?: (temmeId: string, hierarchy: Hierarchy) => void
): object;
validate(hierarchy: object): {
valid: boolean;
error: Error | null;
};Building Temme locally is straightforward. Run:
pnpm prodThat command will:
- remove previous build artifacts from
distandbuild - build the distributable package with
tsup - generate the browser-ready documentation bundle at
docs/assets/js/lib/temme.js
| Command | Description |
|---|---|
pnpm clean |
Deletes the dist and build folders. |
pnpm build |
Builds the package outputs into dist using tsup. |
pnpm dev |
Runs tsup in watch mode for development. |
pnpm build:docs |
Builds the browser bundle used by the docs website. |
pnpm prod |
Runs clean, build, and build:docs. |
pnpm test |
Runs the unit test suite. |
pnpm typecheck |
Runs TypeScript type checking without emitting files. |
pnpm lint |
Runs the linter. |
pnpm lint:fix |
Runs the linter and applies automatic fixes where possible. |
Inheritance is one of Temme’s main composition features. It allows one hierarchy object to reuse options from another object or template so you can reduce duplication and keep your hierarchy definitions concise.
Temme supports three inheritance patterns:
- Object to Object: a rendered hierarchy object inherits from another rendered hierarchy object in a valid scope.
- Object to Template: a rendered hierarchy object inherits from a template.
- Template to Template: a template inherits from another template.
Templates are never rendered directly, which makes them ideal for reusable presets and shared definitions.
The primary inheritable options are:
attributeschildNodesclassescontentdatasetidname
const hierarchy = {
ref: "parent",
childNodes: [
{
from: {
ref: "parent"
}
}
]
};A referencing hierarchy object uses the from option to describe what it inherits and how the inheritance should behave.
The from option supports:
-
ref: the referenced object or template -
mode: inheritance mode (appendoroverride) -
include: inherit only specific options -
exclude: ignore specific options -
children: control whether inherited children are included and where they are placed
const hierarchy = {
ref: "parent",
attributes: { visible: true },
classes: ["red", "blue"],
childNodes: [
{
ref: "sibling",
name: "h1",
classes: ["yellow"],
dataset: {
id: 100,
title: "Some title"
},
from: {
ref: "parent"
}
},
{
name: "p",
from: {
ref: "sibling"
}
}
]
};In this example:
- the first child inherits from
parent - the second child inherits from
sibling - inherited values accumulate as references are resolved
Temme also normalizes inherited arrays such as classes by removing duplicates and sorting values.
const hierarchy = {
templates: [
{
ref: "temp-1",
classes: ["bold", "dup", "dup"]
},
{
ref: "temp-2",
from: {
ref: "temp-1"
},
classes: ["orange", "dup"]
}
],
from: {
ref: "temp-2"
}
};Here:
-
temp-2inherits fromtemp-1 - the root hierarchy inherits from
temp-2 - duplicate class values are removed during normalization
Templates can inherit from templates, but templates cannot reference non-template rendered objects.
Temme lets you control inheritance scope through include and exclude.
const hierarchy = {
templates: [
{
ref: "temp-1",
attributes: {
visible: true,
counter: 56
},
classes: ["some-class"],
dataset: { id: 814 }
}
],
from: {
ref: "temp-1",
include: ["classes", "dataset"]
}
};This inherits only classes and dataset.
const hierarchy = {
templates: [
{
ref: "temp-1",
attributes: {
visible: true,
counter: 56
},
classes: ["some-class"],
dataset: { id: 814 }
}
],
from: {
ref: "temp-1",
exclude: ["dataset"]
}
};This inherits everything except dataset.
include and exclude are mutually exclusive and should not be used together.
Child inheritance is controlled through the children sub-option inside from.
const hierarchy = {
childNodes: [
{
ref: "list",
name: "ul",
childNodes: [
{ name: "li" },
{ name: "li" }
]
},
{
from: {
ref: "list",
children: {
allow: true
}
},
childNodes: [
{
name: "span"
}
]
}
]
};When children.allow is true, the referenced node’s children are inherited as well.
You can also control placement:
from: {
ref: "list",
children: {
allow: true,
placement: "before"
}
}placement accepts:
"before""after"
The default is "after".
Temme supports two inheritance modes:
This is the default mode.
- primitive values are preserved on the inheriting object when already present
- arrays are merged
- objects are appended without overwriting existing keys in the inheriting object
- primitive values are overwritten by the referenced object
- arrays are replaced by the referenced value
- objects overwrite matching keys and keep non-conflicting ones
Example:
const hierarchy = {
templates: [
{
ref: "base",
id: "main-id",
classes: ["one", "two"]
}
],
from: {
ref: "base",
mode: "override"
}
};Use append when you want additive composition, and override when you want the referenced structure to take precedence.
Temme gives you a declarative, object-based way to generate HTML with JavaScript.