Links that don’t go anywhere should be buttons Tuesday, February 5th, 2019 at 12:34 pm

This morning I tweeted a blog post about Back to Basics: Non-Navigating Links for JavaScript Handling and rightfully incurred the wrath of the Gunnar pointing out the flaws of the article.

In essence, the article asks which of the five following examples is the correct one to create a link that invokes some JavaScript functionality:

<a href = "" > <a href = "#" > <a href = "#" onclick = "return false;" /> <a href = "javascript:void(0)" > <a href = "javascript:{}" > <a href = "#0" > <a href=""> <a href="#"> <a href="#" onclick="return false;" /> <a href="javascript:void(0)"> <a href="javascript:{}"> <a href="#0">

The correct answer is none. This is not what anchors < a > are for. An anchor element should have a href attribute that points to a valid URL resource. In other words:

You use an anchor if you want to create an interactive element in the your site or app that takes you to another web resource. You do not use an anchor element to trigger scripting functionality. That’s what the button element is for.

Both are simple to use and come with a boatload of accessibility benefits, like keyboard access and native state indicators in the browser.

When to use an anchor/link

You use an anchor element when you link to a URL or an API endpoint:

<a href = "https://www.w3.org/TR/html52/interactive-elements.html" > Interactive elements in HTML </a > <a href = "/inbox" > Inbox </a > <a href="https://www.w3.org/TR/html52/interactive-elements.html">Interactive elements in HTML</a> <a href="/inbox">Inbox</a>

Or when you link to a destination in the same document:

<a href = "#terms" > Our Terms and Conditions for you to ignore </a > ... truckloads of HTML ... <div id = "terms" > ... </div > <a href="#terms">Our Terms and Conditions for you to ignore</a> ... truckloads of HTML ... <div id="terms">... </div>

You can then use JavaScript to intercept the link and overwrite its default behaviour to keep the users on the page. If JavaScript fails for some reason, users will reload the whole UI and still go to where they need to go. In this example to the w3c web site, the /inbox endpoint UI for your app or the terms DIV. They could also open any of those in another tab. I do that all the time in WordPress. This is good, solid, design that keeps the user in control. However, when there is no URL or in-page target to go to, you give a promise you don’t keep.

When to use buttons

If, your app has no URL endpoints for the different states and all the handling happens in JavaScript, there is no point in confusing your users with a link that goes nowhere and won’t open anything in another tab. Use a button and you won’t promise any functionality you don’t have.

<button > Inbox </button > <button>Inbox</button>

This HTML element is custom made exactly for that purpose and works fine – even with a keyboard.

Buttons even work without JavaScript. If you put them in a form element pressing them will send the form data to the server and you can react to which button was pressed in your backend. Of course you can also override this functionality and do all in the script – you just need to hope that it will work.

Don’t confuse users

This is especially important when it comes to accessibility concerns. Screen reader users, for example, can navigate a document in various ways. One of them is getting a list of all the links in the document. This prevents them from having to listen to the whole document to find a certain part of it. If you create a lot of links that point nowhere, you fill this list with nonsense. If you create buttons and label them accordingly, even people who can’t see your UI will be able to navigate it.

Why is this still a problem?

Fans of markup and a simple web know this for ages and we keep having to repeat it every few years. Yet, links keep getting used for functionality that doesn’t go anywhere on the web or in the document.

The reasons are largely historical and cargo-cult horror stories of browsers doing things wrong. Browser of the past had a few issues with buttons. It was tough to override their in-browser style. Very old versions of Internet Explorer had a bug that only the first button was included in the form data, not the one that was pressed.

Styling is probably still the main reason why people wrongly use a link where a button should be used. Buttons are much more complex interaction elements than links and they have more styles attached to them. Links are part of the text renderer, buttons are traditionally part of forms and much more complex. So if someone who doesn’t like CSS and is worried about “things looking wrong”, it is tempting to use a link as it is easier to style. That, however, is an indicator that there is something wrong with the project management of your product. End users shouldn’t get the wrong interaction model because the person who had to style the product doesn’t know how to or want to.

The last reason is probably that it works and we’ve seen other people do it. That’s an entitled and lazy reason. Browsers have to be forgiving in what they show to avoid end users getting a broken experience. However, not everybody has the same setup, abilities and ideas what a great interface is that we have. By using the right element for the right job, we hand a lot of the responsibility to create a working interface to the browser and the OS instead of having to do it ourselves. Just because links don’t break for us doesn’t mean they don’t for others when a button is a much sturdier, custom-made solution.

The issues with buttons in older browsers have been fixed now. There is no excuse these days not to use a button, especially when considering how much accessibility benefits you get for free.