domogen
v0.0.21
Published
Domogen is a dependency-free and lightweight library for generating HTML with support for efficient and parameterized inline styling.
Downloads
6
Readme
Domogen
Domogen is a dependency-free and lightweight library for generating HTML with support for efficient and parameterized inline styling.
Installation
Install via:
npm install domogen
Usage
We will create an HTML document by calling the Root
constructor:
import { Root } from "domogen"
const root = new Root()
Basics
We can start constructing sections of the HTML document by using HTMLNode
, RawNode
and TextNode
. HTMLNode
allows you to construct an HTML element, set attributes on it and set its children. RawNode
is for encapsulating raw, unescaped HTML, whilst TextNode
performs escaping on the text provided. See the example below for reference:
import { HTMLNode, TextNode, RawNode } from "domogen"
const div = new HTMLNode("div")
.addAttribute("width", "500px")
.addChild(new TextNode("this is escaped text"))
.addChild(new HTMLNode("span")
.addChild(new RawNode("this is unescaped HTML"))
)
Fragments
We can also use FragmentNode
- this is similar to a ReactFragment
you might find in React. It allows you to render a collection of child elements without having to wrap them in an additional HTML element:
import { FragmentNode } from "domogen"
const fragment = new FragmentNode()
.addChild(new TextNode("h"))
.addChild(new TextNode("i"))
// div renders to <div>hi</div>
const div = new HTMLNode("div")
.addChild(fragment)
Components
We can use what we've learnt to construct complex, HTML components, similar in function to React components, allowing for maximal code re-use. Lets create an example "InfoBox" component below that will take a blurb of text, and present it in a padded, bordered box:
import type { INode, RenderContext } from "domogen"
export const InfoBox {
private rootNode : INode
constructor(text : string) {
this.rootNode = new HTMLNode("div")
.addAttribute("style", "padding:4px;border 1px solid black;")
.addChild(new TexNode(text))
}
render(context : RenderContext ) {
// To render this node, we simply render its root node
this.rootNode.render(context)
}
}
We have created a class that implements the core INode
interface (specifically, the render
method). Once constructed, this node can be passed into any addChild
method (they accept INode
implementations):
const div = new HTMLNode("div")
div.addChild(new InfoBox("hello test"))
Head
Sometimes its nice to create components that, upon render, will mutate the <head>
, despite being placed in the <body>
. This can be achieved by using a HeadCollectorNode
:
import { HeadCollectorNode } from "domogen"
export class Title {
private rootNode : INode
constructor(title : string) {
this.rootNode = new HeadCollectorNode()
.addChild(new HTMLNode("title")
.addChild(new RawNode(title))
)
}
render(context : RenderContext) {
this.rootNode.render(context)
}
}
const div = new HTMLNode("div").addChild(new Title("foo"))
Now, upon render, the Title
component will not render anything inside the div
, but instead will append its children to the <head>
tag.
Inline Styling
And now, for the pièce de résistance, inline styling. To style an HTMLNode
, we first must create a StyleFactory<T>
, which will take some parameters T
, and return a Style
which can be applied directly to an HTMLNode
as follows:
import { StyleFactory } from "domogen"
const simpleStyleFactory = new StyleFactory<{ padding : number }>((clsName, params) => {
// The StyleTemplate (that the StyleFactory takes in its constructor)
// generates a valid chunk of CSS for a given className and set of parameters:
const block = [
`padding: ${padding}px;`,
"background-color: black;"
].join("")
return `.${clsName} {${block}}`
})
const div = new HTMLNode("div")
.addStyle(simpleStyleFactory.getStyle({ padding: 5}))
In this example, the CSS generated by the StyleFactory
will be appended to the <head>
and the HTML element will have a corresponding CSS class added to it such that it receives the styling. Should we re-use the exact styles:
const span = new HTMLNode("span")
.addStyle(simpleStyleFactory.getStyle({ padding: 5}))
The generated CSS won't be redundantly added to the DOM, with the span
re-using the same class name as the div
above...