Proper websites, done properly

Accessible external links

6 minute read time / 783 words

TL;DR: Just add the rel="noreferrer" attribute if you need it, and let people decide what they want to do.

You'll probably know you can force a hyperlink to open in a new window or tab by specifying a single attribute with the correct value: target.

<a href="https://google.co.uk" target="_blank">
    Google search (UK)
</a>

But this can be improved. Firstly, there's actually a security consideration. Opening a link in a new window to an external site keep by default will grant new a new browsing context and will mean the site you send people to can use that information. It makes sense to prevent that, so we can do this:

<a href="https://google.co.uk" rel="noreferrer" data-external-link="true"
    >Google search (UK)
</a>

So we've now got an external link that opens in a new window or tab, and is protected from untrusted sites too. But it's still not as accessible as it could be. Screen reader users can be provided an extra bonus with some visually hidden text that warns them about what will happen if they use the link.

<a href="https://google.co.uk" rel="noreferrer" data-external-link="true">
    Google search (UK)
    <span class="vh"> (This link opens in a new window or tab)</span>
</a>
.vh {
    position: absolute;
    overflow: hidden;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
}

So now we're getting somewhere. But how do sighted visitors to your site know this link is external? Well, you can do something as simple as a CSS attribute selector that will allow you to style external links differently to internal links.

a[target="_blank"] {
    position: relative;

    &::after {
        content: '';
        display: inline-block;
        inline-size: 12px;
        block-size: 12px;
        background: transparent url(icon--external.svg) no-repeat 50% 50% / contain;
        transition: .25s translate ease;
    }
}

Update: January 2024

I've used the above technique for a number of years and never seen the need to make any changes. However, in double-checking something recently, I noticed that you no longer need to specify rel="noopener" because it's now implicitly specified whenever you use a target="_blank" in all current major browsers.

If you don't want to send referrer headers in those clicks, you'll still need to add rel="noreferrer" though.

I'm always on the lookout for new or better ways of doing things. When I first used the method for external links, I was dead set against it as I believed that everybody using the Internet would know if a link was external or internal from either the context of the link text, its position in the content or on the site, or by how a screen reader would notify a user of the destination.

This was a battle I lost, so have in the time since, just stuck with that method. After all, it did come from a well-respected third party accessibility testing company. One I did and do trust a lot.

Recently, I read an article about accessible external links because it showed up on a newsletter I am subscribed to and I wanted to see how other people were approaching the issue currently.

The argument there is simple. Give the user the choice. It's like we've gone full circle! If we force opening links in a new window, we remove the user's ability to choose what to do with it.

There are times when you probably have no choice but to open a link in a new window, such as to show terms and conditions in a checkout/form-filling process where opening the link in the current tab would lose progress. But, as with most things, there's probably a better way around that particular issue too. Showing a terms and conditions page is an internal link and opening a new browsing context might feel odd to users, or disorientating for many.

Step forward: the <dialog>. A native solution we can use to save us relying on third party javascript plugins for modal windows and it's already available and is supported by all major browsers.

So, in conclusion, the best, most accessible, and most flexible way to write most external links is this way:

<a href="https://google.co.uk" rel="noreferrer" data-external-link="true">
    Google search (UK)
</a>

I've swapped out target="_blank" for data-external-link="true" so we can still use an attribute selector in our CSS:

a[data-external-link="true"] {
    position: relative;

    &::after {
        content: '';
        display: inline-block;
        inline-size: 12px;
        block-size: 12px;
        background: transparent url(icon--external.svg) no-repeat 50% 50% / contain;
        transition: .25s translate ease;
    }
}

You could even simplify the selector further and do away completely with the data- attribute:

a[href^="http"] { ... }

I've opted (for now at least) to use the data- attribute because it's more explicit. I may change that in the future once I've let the idea perculate a bit longer.

Conclusion: Let your users decide what to do with it.