Static Version

Using HAML templates in JavaScript

One of my favorite libraries when I was doing ruby development was the HTML templating language HAML. For those of you who haven't yet been enlightened, it's an alternate syntax for XML that results is a lot less code to write the same thing.

When I switched to primarily JavaScript I missed HAML so much I wrote a port of it. Two actually. One is called jquery-haml. It's a dom-building library with some really advanced DOM integration tricks. The other is haml-js. It's a text to text compiler that translates HTML code to HTML, perfect for node based websites.

Using haml-js in a node website

Using haml-js is pretty straight forward. First, you install haml-js as a library for use in node. The full docs are here, but I'll show how I set up my node libraries.

Installing haml-js in node

There isn't really a standard package manager in node, but it's not hard to install a package once you've done it a time or two. I like to use git for all github based libraries so that I can update any library by issuing a pull command.

tim@TimBook:~$ mkdir Code
:~$ cd Code/
:~/Code$ git clone git://
Initialized empty Git repository in /Users/tim/Code/haml-js/.git/
: Counting objects: 311, done.
: Compressing objects: 100% (278/278), done.
: Total 311 (delta 161), reused 0 (delta 0)
Receiving objects: 100% (311/311), 47.73 KiB, done.
Resolving deltas: 100% (161/161), done.
:~$ mkdir ~/.node_libraries
tim@TimBook:~$ cd ~/
:~/.node_libraries$ ln -s ~/Code/haml-js/lib/* ./

Here I created a folder in my home folder to contain various code clones. In that directory I cloned the haml-js library. Then I created the .node_libraries directory in my home folder for node to find libraries. From that folder I linked to everything in the lib subfolder of haml-js.

Once you're done this once, you can skip the mkdir commands.

Checking the install

Open up a node-repl session and see if you can import my library.

tim@TimBook:~$ node-repl
Welcome to the Node.js REPL.
Enter ECMAScript at the prompt.
> var Haml = require('haml');
"compile": [Function],
"optimize": [Function],
"render": [Function],
"execute": [Function]
> Haml.render('.classy Hello World')
"<div class=\"classy\">Hello World\n</div>"

Great it's working. If this is not working for you, the node mailing list is a really friendly place if you need help getting this setup.

A simple HAML based site

As you saw in the last section, you can test it from a node-repl session, but let's make a whole program with partials, loops and conditionals just for fun.

Layout template

First let's main our layout template, we'll save it as layout.haml:

!!! Strict
%title&= title
= contents

Start of Program

Now we'll write a short node program to render it

var Haml = require('haml'),
File = require('file'),
= require('sys');'layout.haml').addCallback(function (haml) {
var data = {
: "Hello Node",
: "<h1>Hello World</h1>"
var html = Haml.render(haml, {locals: data});

This program will output:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "">
<html lang="en"><head><title>Hello Node
</title></head><body><h1>Hello World</h1>


Usually you'll want another template for your actual pages and just share the common layout between them. So we'll make an actual page with a little logic in it and save it as users.haml.

%h1 Users
:if users.length === 0
%p There are no users in the system.
:if users.length > 0
:each user in users
%li&= user

First, there are two branches in this template. If the users list is empty then a static message will be shown, if not, then each user will be shown as a list item.

Here is how we modify the code to use this page:'layout.haml').addCallback(function (layout_haml) {'users.haml').addCallback(function (users_haml) {
var data = {
: ["Tim", "Sally", "George", "James"]
var page_data = {
: "System Users",
: Haml.render(users_haml, {locals: data})
var html = Haml.render(layout_haml, {locals: page_data});

And here is the output:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "">
<html lang="en"><head><title>System Users


Ok, now that we know how to make layout templates by passing the result of one template as a variable to another, let's learn how to do partials. Partials are pieces of templates that are shared between several pages.

Here is the data we want to render:

var links = [
{name: "Google", link: ""},
{name: "Github", link: ""},
{name: "nodejs", link: ""},
{name: "", link: ""}

First we'll make a partial to render each link by itself and save it as link.haml:

%a{href: link}&= name

Then we'll make a page to render the links and save it as links.haml

%h1 Links
:each link in links
= partial("link", link)

Since partials aren't built into haml-js, then we'll have to implement it in our framework. But don't worry, it's not hard.

First we're starting to nest pretty deeply, so we'll shift to parallel file loading for the template sources. We'll pre-compile the templates while we're at it:

var template_names = ["layout", "link", "links"];
var counter = template_names.length;
var templates = {};
.forEach(function (name) { + ".haml").addCallback(function (text) {
[name] = Haml.compile(text);
if (counter <= 0) {

Alright, now we can make a render function that knows how to load the saved, compiled templates:

function render(name, locals) {
return Haml.execute(templates[name], null, locals);

Now we're all set to define the render_page function referenced in the parallel loading part.

function render_page() {
var html = render("layout", {
: "Links",
: render("links", {
partial: render,
: links

Source Code

You can find the source code of the code in these examples on GitHub.

Also this blog itself is powered by haml-js. You can see the templates here and the engine here.

Using jquery-haml

My other HAML project, jquery-haml is a different beast altogether. Instead of parsing real HAML syntax and generating HTML text, it takes a JSON structure and don-builds from it. There is nothing stopping you from using the text-to-text haml-js in a browser and inserting it into the DOM using innerHTML, but you can't get at the nodes as they're created because it's all done behind closed doors by the browser.

Here is a simple example of the jquery-haml syntax:

["#date", print_date() ],
["#address", curent_user.address ]
["#email", ],
["#bio", ]

There is nothing special here except we've taken the HAML syntax and fit in into proper JSON syntax.

How about this example though:

["%div", {style: "width:260px; margin:15px;", $:{
: [{value: 60}]

It creates a div element, sets the style on it, and then calls $.fn.slider on it! We didn't have to give it a unique id and then search for it later with something like $("#my_id").slider({value: 60}), the dombuilder library did it for us right after creating the node.

A full depth tutorial on this library could go on for pages, but this should be enough to whet you appetite. See the source of the sample page for some more ideas. But since this is more of an easy macro system for programmatically dom-building, then you have full control over every step. I've written entire apps using just nested jquery-haml expressions using closures for data storage.

View the discussion comments powered byDisqus