htmlforge
v0.0.18
Published

Downloads
387
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 { HTMLDocument, NodeElement, NodeText } from "htmlforge"
const html = new HTMLDocument()
html.attributeAdd("lang", "en-GB")
html.head.childAdd(
new NodeElement("title").childAdd(
new NodeText("Acme Title")
)
)
html.body.childAdd(
new NodeElement("div")
.styleAdd("width", "100%")
.styleAdd("background-color", "blue")
.styleAdd("background-color", "red", { pseudoSelector: ":hover" })
.childAdd(new NodeText("Hello world"))
)
const validHTML = html.toString()Installation
Install the package from npm:
npm install htmlforgeUsage
HTML structure
An HTMLForge HTMLDocument instance is a tree of nodes. Nodes come in a few flavors:
NodeElement: represents tags (e.g.,<div>,<span>), can hold attributes and inline styles, and can nest any other node as a child.NodeText: holds plain text content that will be HTML-escaped.NodeRaw: holds raw HTML without escaping.NodeFragment: groups a collection of child nodes without introducing a wrapping element.
Creating an HTML document
Create a new HTML document using new HTMLDocument(), set attributes on the root <html> element via html.attributeAdd, and work directly with html.head and html.body to populate content. The constructor accepts optional parameters:
indentCount(default4): number of spaces used for pretty-print indentation intoString().signatureDisplay(defaulttrue): whether to include the<!-- Generated by HTMLForge -->signature comment.
import { HTMLDocument, NodeElement, NodeText } from "htmlforge"
const html = new HTMLDocument({ indentCount: 2, signatureDisplay: false })
.attributeAdd("lang", "en")
.attributeAdd("data-theme", "dark")
html.body
.styleAdd("margin", "auto")
.childAdd(new NodeText("Hello world"))NodeElement nodes
NodeElement supports:
attributeAdd(name, value)for HTML attributesstyleAdd(property, value, options?)for inline styles (with optionalpseudoSelector,mediaQueryparameters)childAdd(node)to nest children nodes
These calls are chainable to keep element construction compact.
import { NodeElement, NodeText } from "htmlforge"
const card = new NodeElement("section")
.attributeAdd("aria-label", "profile card")
.styleAdd("border", "1px solid #ccc")
.childAdd(
new NodeElement("h2").childAdd(new NodeText("Ada Lovelace"))
)
.childAdd(
new NodeElement("p")
.styleAdd("color", "#555")
.childAdd(new NodeText("First computer programmer."))
)NodeFragment nodes
NodeFragment groups child nodes without adding a wrapper element. It only supports childAdd (also chainable).
import { NodeFragment, NodeElement, NodeText } from "htmlforge"
const listItems = new NodeFragment()
.childAdd(new NodeElement("li").childAdd(new NodeText("One")))
.childAdd(new NodeElement("li").childAdd(new NodeText("Two")))
.childAdd(new NodeElement("li").childAdd(new NodeText("Three")))Text and Raw nodes
NodeTextholds HTML-escaped text content (no additional methods).NodeRawinjects raw HTML as-is (no additional methods).
import { NodeText, NodeRaw } from "htmlforge"
const safeText = new NodeText("<em>Escaped</em> output")
const rawHtml = new NodeRaw("<em>Unescaped</em> output")Define your own nodes
Implement the INode interface to build reusable components. Compose a private NodeElement (style/shape it however you like) and proxy its build() method. Anything that implements INode can be passed to childAdd on NodeElement or NodeFragment.
import type { INode } from "htmlforge"
import { NodeElement, NodeText } from "htmlforge"
class Alert implements INode {
private readonly el = new NodeElement("div")
.attributeAdd("role", "alert")
.styleAdd("padding", "12px 16px")
.styleAdd("background-color", "#fffae6")
constructor(message: string) {
this.el.childAdd(new NodeText(message))
}
// Optional: expose childAdd to let callers inject arbitrary child nodes
childAdd(child: INode) {
this.el.childAdd(child)
return this
}
build() {
return this.el.build()
}
}