Table of Contents

While working on improvements to this site, I wanted to make sure any external links would open not just in a new tab, but also securely.

I chanced upon this snippet shared by Bradley Gauthier on Sitecast.

The original snippet as at the time of this post:

(function() {
  var links = document.links;
  for (var i = 0, linksLength = links.length; i < linksLength; i++) {
    if (links[i].hostname != window.location.hostname) {
      links[i].target = "_blank";
      links[i].setAttribute("rel", "noopener noreferrer");
      links[i].className += " externalLink";
    } else {
      links[i].className += " localLink";    
    }
  }
})();

Since I find ES2015/ES6 concise while simultaneously aiding code readability, I improved the snippet and included it on my site.

Here is the ES2015 version:

(function(){
    let links = document.links;
    if (links.length) {
        // links is an HTMLCollection, an array-like object.
        // We cannot directly call the forEach method on it.
        // We can use the same function through the Array prototype object.
        Array.prototype.forEach.call(links, link => {
            if (link.hostname != window.location.hostname) {
                link.target = "_blank";
                link.setAttribute("rel", "noopener noreferrer");
                link.classList.add("externalLink");
            }
            else {
                link.classList.add("localLink");
            }
        });
    }
})();

I did gain two bits of JavaScript knowledge thanks to the original snippet and the re-write:

  • document.links1 - create and return an HTMLCollection live object of all the links in the document. This also returns area elements!
  • One cannot directly loop over an HTMLCollection2 by calling the forEach method on the collection. One can, interestingly, use the same iteration function through the Array prototype object to get around this limitation.