A 'not-another-templating-language' for javascripters





GitHub Stars



Last Commit

2yrs ago






Size (min+gzip)




Type Definitions





nant lets you generate your html templates with plain javascript (browser and server).


  • No need to learn another language, just old good javascript
  • Tags are simple POJOs (Plain Old Javascript Object) and can be manipulated with ease before stringification
  • Uses all language constructs and programming techniques to define your reusable building blocks
  • Attach your own methods to specific Tags using Mixins

Get started

On the Browser :

It's just one file - nant.js - to import in your page.

        <script src="nant.js"></script>
        <div id="placeholder">...</div>
            var el = document.getElementById('placeholder');
            var ht =;
            el.innerHTML = ht.p('this is as easy as writing javascript code').toString(); 

On the server

npm install nant


// get the Html Templates namespace
var ht = require('nant').ht;
var html = ht.p('this is as easy as writing javascript code').toString();

Tag creation

Html tags are exposed as functions in the ht namespace and tag attributes are passed as arguments.

var html = ht.input({ type: 'text', name: 'myinput', required: 'true'}).toString();
console.log( html );
<input type="text" name="myinput" required>

Tag body is passed as an optional argument

var html = ht.div({ id: 'myid', class: 'myclass' }, 'String body').toString();
console.log( html );
<div class="myclass" id="myid" required>
    String body

You can pass nested tags as body (note you don'need to call toString() on nested tags)

ht.form({ id: 'myform', class: 'myclass' },
        ht.label('My Input'),
        ht.input({ name: 'myinput', placeholder: 'My Input' })

If you pass a function as body, it will be called upon rendering (with the parent tag as parameter)

function myBody(tag) {
    return ht.p('Hello to ' +;

ht.form({ id: 'myform', class: 'myclass' }, 

if you need to embody multiples tags, simply list them in order

ht.form({ id: 'myform', class: 'myclass' }, 
    ht.label({ for: 'myinput' }, 'My input'),
    ht.input({ id:'myinput', name: 'myinput' }),
    'Help text',

You can also group body tags in arrays

ht.form({ id: 'myform', class: 'myclass' },
    ht.h1('Form header'),
        ht.label({ for: 'myinput' }, 'My input'),
        ht.input({ id:'myinput', name: 'myinput' })

css class attribute can be defined as an array

ht.input({ class: ['class1', 'class2'] })
<input class="class1 class2">

or a conditional object, only members with a truthy value will be picked

ht.input({ class: { class1: 1 < 2, class2: 1 > 2 })
<input class="class1">

you may also use array of both string/conditional object

ht.input({ class: [ 'myclass',  { class1: 1 < 2, class2: 1 > 2 } ])
<input class="myclass class1">

Tag manipulation

all methods of the ht namespace returns an objet of type Tag;

the Tag's prototype exposes a few methods; this is useful if you want to manipulate the tag object before calling .toString()

.attr( attrName [, attrValue ] )

get/set current attribute value

var div = ht.input({ name: 'myinput', class: 'myclass' });

div.attr('name');               // 'myinput'
div.attr('class');              // ['myclass']
div.attr('name', 'newName');    // div.attr('name') === 'newName'

note how class attribute was converted to an Array; internally all tags maintains an Array instance for class attribute

.attr( [ attrName1, attrName2, ...] )

When passed an array, returns an object with given attributes

var div = ht.input({ id:'myid', name: 'myname', placeholder: 'My Input' });
div.attr(['id', 'name']); // { id:'myid', name: 'myname' }

.attr( object )

if you pass it an object, tag's attributes will be extended with object's members

var div = ht.input({ name: 'myinput', class: 'myclass' });

div.attr({ id: 'myid', class: 'class1' });
div.attr('id'); // 'myid'
div.attr('class'); // ['myclass', 'class1']


used to check if tag instance references a css class

var div = ht.input({ name: 'myinput', class: ['myclass',  { class1: 1 === 1, class2: 1 !== 1} ] });

div.hasClass('myclass');            // true
div.hasClass('class1');             // true
div.hasClass('class2');             // false
div.hasClass('myclass class1');     // true
div.hasClass(['myclass', 'class2']);     // false


is another familiar method to to toggle on/off css class references

var div = ht.input({ name: 'myinput', class: ['myclass',  { class1: 1 === 1, class2: 1 !== 1} ] });

// div.hasClass('myclass') == false

div.toggleClass('class2', true);            
// div.hasClass('class2') == true

div.toggleClass('class1', true);           
// nothing changes as class1 is already enabled

div.toggleClass(['myclass', 'class2']);    
// div.hasClass('myclass') == true && div.hasClass('class2') == false

.match( selector )

Another useful method to check weather a tag matches the given selector; note only a small subset of css selectors is supported at the moment You can also supply a function (see example below) to perform tag matching


var divTag = ht.div({ id: 'mydiv', class: ['form', 'group', 'col'] });
var inputTag = ht.input({ id: 'myinput', class: ['control', 'col'] });

// tag name selectors
divTag.match('div');                  // true
inputTag.match('input');              // true
divTag.match('div, input');           // true
inputTag.match(['div', 'input']);     // true

// class names, ids
divTag.match('div.form');               // true
divTag.match('');         // true
divTag.match('#mydiv');                 // true
divTag.match('div#mydiv.form.col');     // true
divTag.match('*.col');                  // true
inputTag.match('*.col');                // true

// uses custom matching method
divTag.match( function(t) {  return === 'div' } );

.children( [ selector ] )

returns all direct children of the current tag; if provided, selector will be used to filter out the result

.find( selector )

returns all descendents (including non-direct children) matching the given selector


Mixins allows attaching custom methods to selected tags

for example, suppose you have a data-model attribute you want to apply to all input tags

//First you define you mixin function
function dataModel(model) {
    return this.attr({ dataModel: model });

// Then you attach it to all <input/> tags
nant.mixin( 'input', dataModel );

therefore you can call input tags with the dataModel method

ht.input({ name: 'myinput' }).dataModel('mymodel');
<input name="myinput" data-model="mymodel">

the exact signature of the nant.mixin() method is

nant.mixin( selector, mixinFn, [mixinName] )


function dataModel() { ... }

// define 'dataModel' methods on all <input/> and <select/> tags
nant.mixin( ['input', 'select'], dataModel );
function tagName(name) { 
    this.attr('name', name);

// define 'name' method on all tags
nant.mixin( '*', tagName, 'name' );
function cols(cols) { 
    this.attr({ class: 'col-sm-'+cols);

// define 'cols' method on all div tags with class 'form-group'
nant.mixin( function(tag) {
    return === 'div' && tag.hasClass('form-group');
}, cols );

Object attributes (for angular/knockout/... users)

nant supports passing nested objects as attribute values, this is useful in some cases (if you're working with data-binding libs like angular or knockout)

    objAttr: { 
        strAttr: 'strAttr', 
        numAttr: 1, 
        nested: { 
            nestedStr: 'nest\'edStr', 
            nestedNum: 1 
<div obj-attr="{strAttr: 'strAttr', numAttr: 1, nested: {nestedStr: 'nest\'edStr', nestedNum: 1}}"></div>

Note also that camelCased tag attribute names are transformed to their dash-delimited countreparts (ie objAttr become obj-attr)

Sometimes, when working with data-binding libs, we have to pass expressions in the object attribute that will be evaluated later by the lib. observe this angular example

<p ng-class="{strike: !deleted, bold: some.isBold() }">...</p>

we can't write this object straight into our code because the expressions will be evaluateed directly

// Error, strike and bold members will get evaluated right now, probably raises an error if deleted or some aren't in the scope
ht.p({ ngClass: {strike: !deleted, bold: some.isBold() } })

instead use nant.uq(expr) to build an unquoted expression

// Correct , strike and bold members will get evaluated later
ht.p({ ngClass: {strike: nant.uq('!deleted'), bold: nant.uq('some.isBold()') } })

Defining Custom Tags


Simply, use nant.makeTag to make a tag builder function

// It's better to define custom tags in their own namespace
var ns = nant.ns = {};
// define your custom element inside the namespace
ns.myElement = nant.makeTag('MyElement', isVoid)

//Later you can use your tag function
var myHtml = ht.div(
    ns.myElement({ ...}, body )

If isVoid parameter is true, then any body provided to the tag function will be ignored and closing tag (</myelement>) will not be generated upon tag stringification


Bootstrap form layout

the following exemple builds a twitter bootstrap form

ht.form({ class: 'form-horizontal', role: 'form' }, 
    ht.div({ class: 'form-group' },
        ht.label({ for:'email', class: ['col-sm-2', 'control-label']}, 'Email'),
        ht.div({ class: 'col-sm-10' },
            ht.input({ type: 'email', class: 'form-control', id: 'email', placeholder: 'Email' })
    ht.div({ class: 'form-group' },
        ht.div({ class: 'col-sm-offset-2 col-sm-10' },
            ht.button({ type: 'submit', class: 'btn btn-default'}, 'Sign in')

As we are simply using javascript, we are free to structure our templating the way we want. So we can also write

var bt = = {};

bt.horzForm = function horzForm() {
    var body =;
    return ht.form({ class: 'form-horizontal', role: 'form' }, body );

//building a formGroup template is as simple as defining functions
bt.formGroup = function formGroup(input, label) {
    return ht.div({ class: 'form-group' },
        ht.div({ class: { 'col-sm-10': true, 'col-sm-offset-2': !label }}, input )

var myHtml = bt.horzForm(
        ht.label({ for:'email', class: ['col-sm-2', 'control-label']}, 'Email'),
        ht.input({ type: 'email', class: 'form-control', id: 'email', placeholder: 'Email' })
        ht.button({ type: 'submit', class: 'btn btn-default'}, 'Sign in')

Lets review the last example, w've reusable bootstrap tags to build form elements.

You may have noted that the grid's columns layout (all those col-sm-* classes) is hard coded inside the templates.

What if we want to move layout defintion (col-sm-* classes) outside ? we can make changes on form layout once and then apply it to all our form template.

// Form layout definition
var layout = {
    label: { class: 'col-sm-2' },
    input: { class: 'col-sm-10' },
    offset: { class: 'col-sm-offset-2' }

// Form group taks care of applying layout definition to its input and label childs
bt.formGroup = function formGroup(input, label) {
    input = ht.div(input).attr(layout.input);
    if(label) {
        label = label.attr(layout.label);
    } else {
        input = input.attr(layout.offset);
    return ht.div({ class: 'form-group' },
        label, input

// Now input and label no longer references bootstrap layout definition
var myHtml = bt.horzForm(
        ht.input({ type: 'email', class: 'form-control', id: 'email', placeholder: 'Email' }),
        ht.label({ for:'email', class: 'control-label'}, 'Email')
        ht.button({ type: 'submit', class: 'btn btn-default'}, 'Sign in')

See how we've decoupled form layout and form field définition.

We can do better by abstracting away more bootstrap grid concepts

function BtFormLayout(cols, media) {
    this.cols = cols; = media;
    this.label = { class: 'col-'+ + '-' + this.cols[0] };
    this.input = { class: 'col-'+ + '-' + this.cols[1] };
    this.offset = { class: 'col-'+ + '-offset-' + this.cols[0] };

var layout = new BtFormLayout([2,10], 'sm');

bt.formGroup = function formGroup(input, label, layout) {
    input = ht.div(input).attr(layout.input);
    if(label) {
        label = label.attr(layout.label);
    } else {
        input = input.attr(layout.offset);
    return ht.div({ class: 'form-group' },
        label, input

var myHtml = bt.horzForm(
        ht.input({ type: 'email', class: 'form-control', id: 'email', placeholder: 'Email' }),
        ht.label({ for:'email', class: 'control-label'}, 'Email')
        ht.button({ type: 'submit', class: 'btn btn-default'}, 'Sign in')

You can go ever further to acheive better reusability; Because you're in the javascript land, you can apply your favourite desgin patterns.

Automatic Bootstrap form generation

//define field config
var userModel = [
    { name: 'fullname', label : 'Full name' },
    { name: 'username', label : 'Username', required: true },
    { name: 'password', label: 'Password', type: 'password' },
    { name: 'email', label : 'Email', type: 'email', required: true }

//template for a single field
bt.field = function (config) {
    return ht.div({ class: 'form-group' },
        ht.label({ for: }, config.label),
        ht.input({ id:, type: config.type, class: 'form-control', 
                placeholder: config.label, required: config.required })

var myHtml = ht.form( bt.field )

Rate & Review

Great Documentation0
Easy to Use0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Unwelcoming Community0