dom-tag

0.1.1 • Public • Published

dom-tag

Templating library. In its purest form dom-tag are just a set of convenience methods wrapping basic DOM manipulation making it simpler to do plain DOM construction.

Installation

$ npm install dom-tag

Tests

$ npm test

Tests are written in mocha and run in node.js with the help of jsdom.

Compatibility

dom-tag does use the following ES5 features:

  • .forEach()
  • .keys()
  • .bind()
  • .map()

If you want use dom-tag in a run time not providing these features, they should be provided as a shim.

Basic usage

Example on building a simple UL list:

var tag = require('dom-tag');
 
var ul = tag.ul({id:'list'},
            tag.li('a'),
            tag.li('b'),
            tag.li('c')
       );

This will create the following HTML:

<ul id="list">
    <li>a</li>
    <li>b</li>
    <li>c</li>
</ul>

API

dom-tag exposes a set of methods which is equal to all known HTML5 elements. When executing one of these methods it will return a HTML Element of the same type as the method name. Iow; to create a <div> element one call the tag.div() method.

So, methods on dom-tag goes like this:

  • .html()
  • .head()
  • .h1()
  • .h2()
  • .h3()
  • .div()
  • .section()
  • .article()
  • .p()
  • .form()
  • etc....

Whitelisting

dom-tag uses a whitelist approach when it comes to which HTML5 elements and attributes one can create.

If one try to use a method which does not correspond to the HTML5 Element whitelist an Error will be thrown. Attributes not corresponding to the HTML Element attribute whitelist will be silently ignored.

Arguments

Each method can take a unlimited number of function agruments. This is the core key to build nested DOM structures with dom-tag.

If a method is passed in as a argument to another method the generated HTML Element will be appended to the generated HTML Element from the method it was passed into.

Iow; when passing the .li() method as an argument to the .ul() like this

tag.ul(
    tag.li()
);

a DOM structure like this will be built:

<ul>
    <li></li>
</ul>

By adding more arguments to the .ul() method:

tag.ul(
    tag.li(),
    tag.li(),
    tag.li()
);

we add more siblings to the DOM structure:

<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>

By passing methods as arguments to the .li() methods again:

tag.ul(
    tag.li(
        tag.b()
    ),
    tag.li(),
    tag.li()
);

we are able to build a deeper DOM structure:

<ul>
    <li>
        <b></b>
    </li>
    <li></li>
    <li></li>
</ul>

There is 3 types of arguments which can be passed to a dom-tag method:

  1. A function. Mostly another method but also any function which returns a DOM node / structure.
  2. A Object where the keys correspond to a set of legal HTML5 Element attributes.
  3. A String.

Attribute object

Attributes on the final HTML Element is set by pasing a Object where the keys correspong to a set of legal HTML5 Element attributes to the method.

To set an id attribute on a HTML Element one simply do like this:

tag.div({id:'foo'});

which will render:

<div id="foo"></div>

Multiple attributes is set by adding multiple key/values in the attribute object:

tag.img({src:'http://img.site.com/bar.webp', alt:'bar pict'});

which will render:

<img src="http://img.site.com/bar.webp" alt="bar pict">

class attribute

class is probably the attribute one set the most. One can use cl as a shorthand key for the class attribute. It will render the same as using class.

Iow, {cl:'foo'} is equal to {class:'foo'}.

style attribute

style is set by providing a Object with style key/value pairs to the key.

Do note that keys which should end up as "-" separated should be written as camelCase. dom-tag will convert it when constructing the attribute.

tag.div({style:{
  backgroundColor : '#000',
  color : '#fff'
}});

will render:

<div style="background-color : #000; color : #fff;"></div>

data-* attributes

data-* attributes is set by providing a Object with data key/value pairs to the key.

Do note that keys which should end up as "-" separated should be written as camelCase. dom-tag will convert it when constructing the attribute.

tag.div({data:{
  foo : 'bar',
  fooBar : 'xyz'
}});

will render:

<div data-foo="bar" data-foo-bar="xyz"></div>

onEvent attributes

None of the onEvent attributes like onClick, onFocus etc is supported due to security reasons. Events should be applied to DOM Elements by .addEventListener().

Wrong and will be ignored:

tag.button(onclick: function(ev){alert('hello')}, 'Click me');

Correct:

var button = tag.button('Click me');
document.querySelectorAll('body')[0].appendChild(button);
 
button.addEventListener('click', function(ev){
  alert('hello');
});

Text

If a String is passed as a value it will be output as a textNode.

tag.p('Foo bar');

will render:

<p>Foo bar</p>

Markup in Strings

dom-tag is based on constructing DOM nodes. Due to security reasons dom-tag does not use innerHTML or provide a HTML parser. If HTML is passed on as a String to dom-tag, the output will be escaped.

tag.p('Foo <b>bar</b> xyz');

will render:

<p>Foo &lt;b&gt;bar&lt;/b&gt; xyz</p>

TIPS

When writing tempates with dom-tag its a good thing to remember that in reality one are doing plain DOM manipulation and that all JS and DOM APIs are available and can be used. This is great power.

But, with great power comes great responsibility. You are responsible of keeping you code clean.

Always try to separate logic from rendering the markup. A good thing is to try to just pass on an Object which contains the values one would like to put into the markup.

In many cases its also worth keeping in mind that any function which returns a DOM element can be pased on to any method in dom-tag. By doing so, its easy to extract logic out of the DOM construction.

Bad:

tag.p((obj.attendees === 0) ? 'None' : obj.attendees.toString());

Good:

function attendees(obj) {
  return (obj.attendees === 0) ? 'None' : obj.attendees.toString();
}
 
tag.p(attendees(obj));

Environments

dom-tags main target is the browser.

Though; with the help of jsdom or window.document dom-tag can run in node.js.

jsdom

jsdom is a full DOM implementation. Using this in production to provide a DOM will probably not fly well due. to the overhead of being a full DOM implementation. Though, for unittesting jsdom is a very good solution.

Example of using dom-tag with jsdom in node.js:

var jsdom = require('jsdom'),
    Tag   = require('dom-tag');
 
// set up a document and tell dom-tag about it
var doc = jsdom.jsdom("<html><body></body></html>", jsdom.level(3, "core")),
    tag = new Tag(doc);
 
// build DOM structures with dom-tag
var html = tag.div({cl:'hello'}, 'world');
 
// dump a string of the DOM structure
console.log(html.outerHTML);

window.document

window.document is a thin shim that fake just the DOM methods needed for constructing DOM trees server side. window.document does not build a full DOM. Instead it does build HTML fragments by concatinating strings. This makes it much more light weight than jsdom which again makes it suitable for rendering markup in a production server.

Example of using dom-tag with window.document in node.js:

var Doc = require('window.document'),
    Tag = require('dom-tag');
 
// set up a document and tell dom-tag about it
var tag = new Tag(new Document());
 
// build DOM structures with dom-tag
var html = tag.div({cl:'hello'}, 'world');
 
// dump a string of the DOM structure
console.log(html.outerHTML);

License

The MIT License (MIT)

Copyright (c) 2014 - Trygve Lie - post@trygve-lie.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Readme

Keywords

Package Sidebar

Install

npm i dom-tag

Weekly Downloads

0

Version

0.1.1

License

MIT

Last publish

Collaborators

  • trygve-lie