@lonnycorp/htmlforge
v0.1.2
Published
 
Readme
HTMLForge
A minimal, zero-dependency library for building fully-styled HTML in TypeScript/JavaScript.
Features
- Zero dependencies.
- Efficient and ergonomic inline styling (using de-duplicated dynamic classes).
- Reusable "Component"-pattern for composing common UIs.
Quick Look
import { Document, node } from "@lonnycorp/htmlforge"
const html = new Document()
html.attribute("lang", "en-GB")
html.head.child(
new node.Element("title").child(
new node.Text("Acme Title")
)
)
html.body.child(
new node.Element("div")
.style("width", "100%")
.style("background-color", "blue")
.style("background-color", "red", { pseudoSelector: ":hover" })
.child(new node.Text("Hello world"))
)
const validHTML = html.toString()Installation
Install the package from npm:
npm install @lonnycorp/htmlforgeUsage
HTML structure
An HTMLForge Document instance is a tree of nodes. Nodes come in a few flavors:
node.Element: represents tags (e.g.,<div>,<span>), can hold attributes and inline styles, and can nest any other node as a child.node.Text: holds plain text content that will be HTML-escaped.node.Raw: holds raw HTML without escaping.node.Fragment: groups a collection of child nodes without introducing a wrapping element.
Creating an HTML document
Create a new HTML document using new Document(), set attributes on the root <html> element via html.attribute, and work directly with html.head and html.body to populate content. The constructor accepts optional parameters:
displaySignature(defaulttrue): whether to include the<!-- Generated by HTMLForge -->signature comment.
import { Document, node } from "@lonnycorp/htmlforge"
const html = new Document({ displaySignature: false })
.attribute("lang", "en")
.attribute("data-theme", "dark")
html.body
.style("margin", "auto")
.child(new node.Text("Hello world"))node.Element nodes
node.Element supports:
attribute(name, value)for HTML attributesstyle(property, value, options?)for inline styles (with optionalpseudoSelector,mediaQueryparameters)child(node)to nest children nodes
These calls are chainable to keep element construction compact.
import { node } from "@lonnycorp/htmlforge"
const card = new node.Element("section")
.attribute("aria-label", "profile card")
.style("border", "1px solid #ccc")
.child(
new node.Element("h2").child(new node.Text("Ada Lovelace"))
)
.child(
new node.Element("p")
.style("color", "#555")
.child(new node.Text("First computer programmer."))
)node.Fragment nodes
node.Fragment groups child nodes without adding a wrapper element. It only supports child (also chainable).
import { node } from "@lonnycorp/htmlforge"
const listItems = new node.Fragment()
.child(new node.Element("li").child(new node.Text("One")))
.child(new node.Element("li").child(new node.Text("Two")))
.child(new node.Element("li").child(new node.Text("Three")))Text and Raw nodes
node.Textholds HTML-escaped text content (no additional methods).node.Rawinjects raw HTML as-is (no additional methods).
import { node } from "@lonnycorp/htmlforge"
const safeText = new node.Text("<em>Escaped</em> output")
const rawHtml = new node.Raw("<em>Unescaped</em> output")Define your own nodes
Implement the node.Buildable interface to build reusable components. Compose a private node.Element (style/shape it however you like) and proxy its build() method. Anything that implements node.Buildable can be passed to child on node.Element or node.Fragment.
import { node } from "@lonnycorp/htmlforge"
class Alert implements node.Buildable {
private readonly el = new node.Element("div")
.attribute("role", "alert")
.style("padding", "12px 16px")
.style("background-color", "#fffae6")
constructor(message: string) {
this.el.child(new node.Text(message))
}
// Optional: expose child to let callers inject arbitrary child nodes
child(child: node.Buildable) {
this.el.child(child)
return this
}
build() {
return this.el.build()
}
}