Have you ever wanted a way to update all file download links on your site to have the behavior of opening a new browser window? This is a better user flow than having the user follow the link and then pressing the back button to get to where they were.

In this simple tutorial, I’ll show you how to do it. I’ll also show you another use case; opening a new window when the link is a to an external site. Two tutorials for the price of one!

You can actually do it without JavaScript, but it requires you to be super vigilant when adding links to your site. Your users may be able to insert links and downloads on your site too, and expecting everyone to remember to do it the “right” way isn’t practical. The way you can do it without JavaScript is using the target attribute.

<a href="some.pdf" target="_new">Really Important Document</a>

You may be saying, “Andrew, didn’t you know that target was deprecated with HTML5?”, to which I’d reply “Yes, but then it isn’t again!” and you’d say “That’s good to know!”.

So we’ll use JavaScript to add the target attribute programmatically to the links we want.

How to do it?

So, imagine you have a link somewhere on your site like this:

<a href="some.pdf">Really Important Document</a>

We need to select the link. We’ll just use plain old JavaScript for this.

var pdfAnchors = document.querySelectorAll("a[href$='.pdf']");

We’re using the CSS selector a[href$='.pdf'] meaning all links that end with ($) the extension .pdf. Most modern browsers can use querySelectorAll. Since this behavior is a “nice to have”, I’m not worried if this doesn’t work in an older browser.

Next we can cycle over each link and set the target attribute to "_new". You could put anything here. But you’ll see "_new" used in most places meaning new window. The target attribute is a reference to a window. All links with the same target will be opened up in that window. We could easily do something like "download" instead.

for(var i = 0; i < pdfAnchors.length; i++) {
    pdfAnchors[i].target = "_new";  
}

This works! However, this could break existing links with targets that are supposed to be there for whatever reason. For example loading something in an iframe.

<a href="some.pdf">Really Important Document</a>
<a href="someOther.pdf" target="special_iframe_target">Another Important Document</a>

We can do something like this:

for(var i = 0; i < pdfAnchors.length; i++) {
    pdfAnchors[i].target =  pdfAnchors[i].target || "_new"; 
}

It’ll assign the target‘s value to be the same value if it already exists, or if it doesn’t exist, it’ll assign the target to "_new".

And that’s it.

Dealing with External Links

Another reason you’d want to open up links in a new window is if you’re going to an external site.

This time you want to check all the links on the page. Conveniently there’s a collection of links on the document object. This is available in any browser with even the most basic API for the DOM implemented.


for(var i = 0; i < document.links.length ; i++) {

}

When we cycle over each link we want to compare the host of the link to the host of the window. If they don’t match we want to create the target attribute.

for(var i = 0; i < document.links.length ; i++) {
    var link = document.links[i];
    var linkHost = link.href.split("/")[2];
    if(linkHost !== window.location.host) {
        link.target = link.target || "_external";
    }
}

Even if your links are relative when you access it programmatically they are absolute URLs. The following HTML hosted on example.com…

<a href="/about">About</a>

…would have the href property of http://example.com/about. So if you were to split it on / the 3rd or index number 2 will be the host. Which is handy!

Conclusion

And, there you have it. Here’s how the examples look together:

<!DOCTYPE html>
<html>
    <body>
        <a href="thisisapdf.pdf">This is a PDF</a>
        <a href="thisisapdf.pdf" target="special_iframe_target">This is a PDF opening in an iframe</a>

        <a href="http://duckduckgo.com">An external link</a>

        <a href="http://duckduckgo.com" target="special_iframe_target">This opens in a special iframe</a>

        <iframe width="200px" height="200px" frameborder="0" id="special_iframe_target">

        </iframe>
        <script>
            var pdfAnchors = document.querySelectorAll("a[href$='.pdf']");

            for(var i = 0; i < pdfAnchors.length; i++) {
                pdfAnchors[i].target = pdfAnchors[i].target || "_new";  
            }


            for(var i = 0; i < document.links.length ; i++) {
                var link = document.links[i];
                var linkHost = link.href.split("/")[2];
                if(linkHost !== window.location.host) {
                    link.target = link.target || "_external"    
                }
            }

        </script>
    </body>
</html>

Ideally you’d want to manually have the target set on the links that you need. But with intelligent client-side programming you can add that behaviour without too much headache and progressively enhance the HTML that’s already there.

If you’re interested in what else you can do with the DOM you can try our Interactive Web Pages with JavaScript course.