Thinking Inside The Box With Vanilla JavaScript

About The Author

Louis is a front-end developer, writer, and author based in Toronto, Canada. He curates the newsletters Web Tools Weekly and VSCode.Email and blogs about … More about Louis ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

Sometimes the simplest JavaScript features are sitting right under our noses and we just haven’t had a lot of exposure to them. In this article, Louis Lazaris won’t be talking about jQuery, and he won’t be looking at structural code concepts or patterns. Instead, he is going to introduce you to some pure JavaScript features that you can use today and that you might not have ever considered before.

During the past four or five years of blogging regularly and doing research for other writing projects, I’ve come across probably thousands of articles on JavaScript.

To me, it seems that a big chunk of these articles can be divided into two very general categories:

  1. jQuery;
  2. Theory and concept articles focused on things like IIFEs, closures and design patterns.

Yes, I’ve likely stumbled upon a ton of other articles that don’t fall into either of these categories or that are more specific. But somehow it feels that most of the ones that really get pushed in the community fall under one of the two categories above.

I think those articles are great, and I hope we see more of them. But sometimes the simplest JavaScript features are sitting right under our noses and we just haven’t had a lot of exposure to them. I’m talking about native, more-or-less cross-browser features that have been in the language for some time.

So, in this article, I won’t be talking about jQuery, and I won’t be looking at structural code concepts or patterns. Instead, I’m going to introduce you to some pure JavaScript features that you can use today and that you might not have ever considered before.

insertAdjacentHTML()

Years ago, Microsoft introduced a method called insertAdjacentHTML() as a way to insert a specified string of text as HTML or XML into a specific place in the DOM. This feature has been available in Internet Explorer (IE) since version 4. Let’s see how it works.

Suppose you have the following HTML:


<div id="box1">
    <p>Some example text</p>
</div>
<div id="box2">
    <p>Some example text</p>
</div>

And suppose you want to insert another snippet of HTML between #box1 and #box2. You can do this quite easily using insertAdjacentHTML():


var box2 = document.getElementById("box2");
box2.insertAdjacentHTML('beforebegin', '<div><p>This gets inserted.</p></div>');

With that, the generated DOM ends up like this:


<div id="box1">
    <p>Some example text</p>
</div>
<div><p>This gets inserted.</p></div>
<div id="box2">
    <p>Some example text</p>
</div>

The insertAdjacentHTML() method takes two parameters. The first defines where you want to place the HTML, relative to the targeted element (in this case, the #box2 element). This may be one of the following four string values:

  • beforebegin The HTML would be placed immediately before the element, as a sibling.
  • afterbegin The HTML would be placed inside the element, before its first child.
  • beforeend The HTML would be placed inside the element, after its last child.
  • afterend The HTML would be placed immediately after the element, as a sibling.

Again, these are string values, not keywords, so they must be placed inside of single or double quotes.

The second parameter is the string you want to insert, also placed in quotes (or else it would be a variable holding a string that was previously defined). Note that it should be a string, not a DOM element or element collection; so, it could just be text, with no actual markup.

insertAdjacentHTML() has, as outlined in a post on Mozilla Hacks, a couple of advantages over something more conventional, like innerHTML(): It does not corrupt the existing DOM elements, and it performs better.

And if you’re wondering why this one hasn’t received a lot of attention so far, despite being well supported in all in-use versions of IE, the reason is probably that, as mentioned in the Mozilla Hacks article, it was not added to Firefox until version 8. Because all other major browsers support this, and Firefox users have been auto-updating since version 5, it’s quite safe to use.

For more on this method:

getBoundingClientRect()

You can obtain the coordinates and, by extension, the dimensions of any element on the page using another lesser-known method, the getBoundingClientRect() method.

Here’s an example of how it might be used:


var box = document.getElementById('box'),
    x, y, w;

x = box.getBoundingClientRect().left;
y = box.getBoundingClientRect().top;

if (box.getBoundingClientRect().width) {
  w = box.getBoundingClientRect().width; // for modern browsers
} else {
  w = box.offsetWidth; // for oldIE
}

console.log(x, y, w);

Here, we’ve targeted an element with an ID of box, and we’re accessing three properties of the getBoundingClientRect() method for the #box element. Here’s a summary of six fairly self-explanatory properties that this method exposes:

  • top How many pixels the top edge of the element is from the topmost edge of the viewport
  • left How many pixels the left edge of the element is from the leftmost edge of the viewport
  • right How many pixels the right edge of the element is from the leftmost edge of the viewport
  • bottom How many pixels the bottom edge of the element is from the topmost edge of the viewport
  • width The width of the element
  • height The height of the element

All of these properties are read-only. And notice that the coordinate properties (top, left, right and bottom) are all relative to the top-left of the viewport.

What about the if/else in the example from above? IE 6 to 8 don’t support the width and height properties; so, if you want full cross-browser support for those, you’ll have to use offsetWidth and/or offsetHeight.

As with insertAdjacentHTML(), despite the lack of support for width and height, this method has been supported in IE since ancient times, and it has support everywhere else that’s relevant, so it’s pretty safe to use.

I will concede something here: Getting the coordinates of an element using offset-based values (such as offsetWidth) is actually faster than using getBoundingClientRect(). Note, however, that offset-based values will always round to the nearest integer, whereas getBoundingClientRect()’s properties will return fractional values.

For more info:

TheAPI

If you’ve ever manipulated elements on the fly with JavaScript, then you’ve likely used methods such as createElement, removeChild, parentNode and related features. And you can manipulate HTML tables in this way, too.

But you may not realize that there is a very specific API for creating and manipulating HTML tables with JavaScript, and it has very good browser support. Let’s take a quick look at some of the methods and properties available with this API.

All of the following methods are available to be used on any HTML table element:

  • insertRow()
  • deleteRow()
  • insertCell()
  • deleteCell()
  • createCaption()
  • deleteCaption()
  • createTHead()
  • deleteTHead()

And then there are the following properties:

  • caption
  • tHead
  • tFoot
  • rows
  • rows.cells

With these features, we can create an entire table, including rows, cells, a caption and cell content. Here’s an example:


var table = document.createElement('table'),
    tbody = document.createElement('tbody'),
    i, rowcount;

table.appendChild(tbody);

for (i = 0; i <= 9; i++) {
  rowcount = i + 1;
  tbody.insertRow(i);
  tbody.rows[i].insertCell(0);
  tbody.rows[i].insertCell(1);
  tbody.rows[i].insertCell(2);
  tbody.rows[i].cells[0].appendChild(document.createTextNode('Row ' + rowcount + ', Cell 1'));
  tbody.rows[i].cells[1].appendChild(document.createTextNode('Row 1, Cell 2'));
  tbody.rows[i].cells[2].appendChild(document.createTextNode('Row 1, Cell 3'));
}

table.createCaption();
table.caption.appendChild(document.createTextNode('A DOM-Generated Table'));

document.body.appendChild(table);

The script above combines some customary core DOM methods with methods and properties of the HTMLTableElement API. The same code written without the table API might be considerably more complex and, thus, harder to read and maintain.

Once again, these table-related features have support all the way back to IE 7 (and probably earlier) and everywhere else that’s relevant, so feel free to use these methods and properties where you see fit.

For more info:

  • HTMLTableElement,” Mozilla Developer Network
  • “Tabular Data,” in the “HTML” specification, WHATWG

Wrapping Up

This discussion of specific native JavaScript features has been a reminder of sorts. We can easily become comfortable with the features of a language that we know well, without looking deeper into the language’s syntax for simpler and more maintainable ways to solve our problems.

So, from time to time, look inside the box, so to speak. That is, investigate all that vanilla JavaScript has to offer, and try not to rely too much on plugins and libraries, which can unnecessarily bloat your code.

(Credits of image on front page: nyuhuhuu)

Further Reading

Smashing Editorial (al, ea, mrn)