2006 / August 9th/ Better living through DOM builders
I’ve been working pretty heavily with JavaScript these past few weeks — specifically parsing XML & JSON. I found out pretty early on that while modifying the DOM with JavaScript is fairly painless, building elements was not so easy. In fact, one might call the situation horrid. Let’s take a walk through a quick example to see how ugly building elements through the DOM really is.
Let’s try and create a nice little snippet of XHTML like the following four lines of code:
<div class="result" id="first_result">
<h3 class="heading"><a href="#">Heading</a></h3>
<p>Small description goes here</p>
</div>
Easy enough, right? I’ll just dive right into my text editor and start hacking away. Here’s the resulting JavaScript:
var result_div = document.createElement('div');
result_div.className = 'result';
result_div.setAttribute('id','first_result');
var heading = document.createElement('h3');
heading.className = 'heading';
var heading_link = document.createElement('a');
heading_link.setAttribute("href", "#");
var heading_link_text = document.createTextNode('Heading');
heading_link.appendChild(heading_link_text);
heading.appendChild(heading_link);
var desc = document.createElement('p');
var desc_text = document.createTextNode('Small description goes here');
desc.appendChild(desc_text);
result_div.appendChild(heading);
result_div.appendChild(desc);
Say, what!? That’s a whole fifteeen lines of JavaScript to render four lines of XHTML. That’s just unacceptable in my book. You’ll even notice I have to drop down to use .className (due to IE) which is just plain nasty. There has to be a better way.
Enter the DOM Builders
It didn’t take me too long to figure out that a nice DOM building library would be of immense help. For this particular project I was working on, all open-source scripts needed to be approved by the client — so I was limited by what I could use. Luckily for me, script.aculo.us had already been approved and was residing on the server. For those of you not aware, script.aculo.us is a lot more than just an effects library. For my particular usage, I was using the nice lean 4kB builder.js (which actually does not require prototype.js).
Builder has one public method, Builder.node(). It accepts three optional arguments: node name, attributes, and children. In usual prototype way, the syntax is utterly beautiful. Builder.node(”p”, { class: ‘test’ }, ‘Hello, World!’) behaves as one would expect, rendering <p class=”test”>Hello, World</p>.
Let’s revisit our snippet of XHTML, this time using builder.js:
var result_div =
Builder.node('div', {class: 'result', id: 'first_result'}, [
Builder.node('h3', {class: 'heading'}, [
Builder.node('a', {href: '#'}, "Heading")
]),
Builder.node(’p', “Small description goes here”)
]);
Nice! Now that’s some syntax I could get used to real quick. One of the nicest features of Builder is that when you pass an array (things wrapped around [ ]) to the second or third argument of Builder.node(), it will automatically add the elements as children and/or textNodes (depending on what you pass on).
Downsides to builder.js
As with any library, there are undoubtedly some cons to using this approach. The biggest one for builder.js is that you’re not actually using the DOM to create all these elements, you’re using the non-standard innerHTML instead. This alone makes some DOM purists mad enough to start spitting fire and heating up their cauldrons of tar. The upside of this downside is that it improves performance dramatically. Still, it’s something to take note of since most DOM builders take this path.
14 Comments
Make a Comment
don’t be afraid, it’s just text

Warpspire is the place that web professional Kyle Neath writes about the web. 


August 9th | #
Really interesting — I too have been looking into JavaScript considerably more these past few weeks and while I still have a lot I’d like to read and learn, this seems like a really neat idea. Thanks for sharing!
August 9th | #
I was just about to say that this comes with a performance hit until I read the last few lines of this entry. Are you talking about the builder that comes with scriptaculous, because I was under the impression that that used typical DOM methods rather than innerHTML.
August 9th | #
Duh :/
August 10th | #
Have you had a chance to look these other solutions?
http://www.vivabit.com/bollocks/2006/04/06/introducing-dom-builder
http://mg.to/2006/02/27/easy-dom-creation-for-jquery-and-prototype
September 3rd | #
Forget all this DOM bullshit. Yurts are the wave of the future.
March 17th | #
DOM Builders
April 27th | #
the correct syntax is:
Builder.node(’div’, {className: ‘result’…
and not:
Builder.node(’div’, {class: ‘result’…
Using “class:” instead of “:className:” will make the whole .js file unreadable under Safari (v2)!!! (it took me hours to figure it out)
September 17th | #
builder.jsrequiresprototype.js.You might want to checkout this, http://nearfar.org/text/dom-builder.html
September 17th | #
Sridhar Ratnakumar: It most definitely does not. I understand you’d like to promote your own solution (I never said script.aculo.us was the only solution — I said quite the opposite). But please do not spread misinformation.
September 23rd | #
Kyle,
Do you or do you not realize that using prototypejs’s functions like
escapeHTML,gsub, etc. would make the script dependent on it?September 23rd | #
Ah, well it seems they’ve changed it. at the time of writing this (over a year ago) it did not require prototype (in fact, I was using it on a site w/o prototype). Not sure what the rational behind that is.
October 29th | #
Actually, prototype now proposes his own version of the DOM Builder (with new Element()), so it’s the other way around : you don’t need script.aculo.us anymore XD
June 7th | #
Thank you for sharing this solution. I have been experience so much pain to create simple html with many many line of dom creation, and doesn’t work in IE sometimes. Thanks.
July 11th | #
ok I know this is ages old but on the off chance someone spots this and can help fix it! :-)
When I insert the following it fall apart. I guess I have my )] etc all muddled.
Builder.node(’div’, {id:’imageDataContainer’},
Builder.node(’div’,{id:’imageData’}, [
Builder.node('div',{id:'imageDetails'}, [
Builder.node('span',{id:'caption'}),
Builder.node('span',{id:'numberDisplay'})
//---------------------------new div
Builder.node('div',{id:'hoverNav'}, [
Builder.node('a',{id:'prevLink', href: '#' },"PREV"),
Builder.node('a',{id:'nextLink', href: '#' },"NEXT")
]),
//—————————-end div
]),
Builder.node(’div’,{id:’bottomNav’},
Builder.node(’a',{id:’bottomNavClose’, href: ‘#’ },
Builder.node(’img’, { src: LightboxOptions.fileBottomNavCloseImage })
)
)
])
)