HTML and DOM generation using javascript data structures

This module generates HTML markup strings and DOM structures for browser and server-side applications. It uses a simple recursive javascript data structure format that mirrors these UI structures while cleanly representing them within javascript code.



Utilities for generating HTML using native javascript data structures: markup produces an HTML string, dom builds a DOM structure using the client browser API, and css renders CSS from an object representation.


In markup, node represents an HTML node. An object is translated to an element using its first key and value as the tag name and content, respectively:

{div: 'hello world'} → <div>hello world</div>

If the value is itself an object, it is interpreted as the element's attributes:

{label: {for: 'name'}} → <label for="name"></label>

Inside an attributes object, the children key is interpreted as a node:

{label: {for: 'name', children: 'Name'}} → <label for="name">Name</label>

If node is an array, markup is recursively called on its elements:

{ul: [{li: 'first'}, {li: 'second'}]} → <ul><li>first</li><li>second</li></ul>

If node is a function, it is output as a self-invoking function '('+node+'('+toString(node.args)+'));', where toString serializes elements in an args array property of the function (if present); functions in the args array are stringified and other values are JSON-encoded. This allows client-side scripts to be inlined into markup generated on the server and run on the client with any needed data passed in:

markup({script: Object.assign(function(square, numbers) {
  console.log(; // prints 1,4,9
}, {
  args: [
    function(x) { return x * x; },
    [1, 2, 3]


<script>(function(square, numbers) {
  console.log(; // prints 1,4,9
}(function(x) { return x * x; },[1,2,3]));</script>

Note that any function used as a node or passed as an argument to it will not have access to values in the server context, so functions accessing only known client-side global variables should be used.

If node is a number, it is treated as a string. Other data types return '', so boolean operators can be used to toggle sections of markup. Within elements in the markup, & and < are encoded as &amp; and &gt;, and within element attributes, & and " are encoded as &amp; and &quot;.


dom represents HTML the same way as markup, but operates on the DOM API, generating and attaching DOM elements and text nodes rather than concatenating strings. Hence, attributes can be applied recursively however the client DOM API allows:

{div: {style: {display: 'block'}}} ←→ document.createElement('div').style.display = 'block';

This also allows event handlers to be attached as attributes:

{div: {onclick: function(event) { alert('clicked!'); }}}

If node is a function (in contrast to its treatment in markup) it is invoked with the parent DOMElement as its first argument, and dom continues to operate on its return value as a node substructure. This way, references to elements can be intercepted for later use as the node structure is constructed.

If parent is a DOMElement, the structure is appended to it. If clear is true, dom first removes all children of parent (if set). dom returns the DOMNode corresponding to the top level of node created, or parent if node is an array.


Generates a string of CSS from its object representation. The styles object consists of selectors as keys mapping to objects with CSS property keys (in camelCase) and values. Descendant selectors (identified by object type values) can also be specified recursively within a parent selector's styles. If & is present within the child selector, its resolved parent selector will be inserted there instead. If a top-level styles key begins with '@media', its value object is treated as an embedded styles object wrapped with the media query.