Posted by Ancestry Team on September 2, 2014 in Development

Semantic buttons and links are important for usability as well as accessibility. Hyperlinks indicate a URL change, whereas buttons are used to perform an action. I thought this post up in response to a question asked on Stack Overflow over 5 years ago.

Which one should you use?

  1. <a href="#" onclick="doSomething()">Do Something</a>
  2. <a href="javascript:void(0);" onclick="doSomething()">Do Something</a>
  3. <a href="javascript:doSomething()">Do Something</a>
  4. <a href="" ng-click="app.doSomething()">Do Something</a>

Answer: None of those!

All elements in HTML (except for <div> and <span>) have a semantic meaning. This semantic meaning is interpreted by browsers, screen readers, and SEO crawlers. Browsers use this semantic value to properly display the elements and to bind interactions. Screen readers also use this semantic value to bind additional different keyboard shortcuts and interactions. Lastly, SEO crawlers use this meaning to measure importance of content and define relationships.

The above examples are using the <a> element to solely perform a JavaScript action. This is incorrect, as the semantic meaning of an <a> element as defined by the W3C is as follows:

The <a> element represents a hyperlink.

A hyperlink is “a link from a hypertext file or document to another location or file.1“. Since those examples are not linking to another location, they are incorrect.

So what is the correct element to use when its sole purpose is to perform a JS action? That would be the <button> element.

The <button> element with a type attribute whose value is "button" represents a button with no additional semantics.

I feel that this documentation could be slightly improved to imply that a “button” means the element should be “clickable” or “interactive.” Applying these definitions, the correct answer would be marked up like so:

<button type="button" onclick="doSomething()">Do Something</button>

Semantic buttons provide a cross-browser focusable area and indicate an interaction is expected. If you read no further than this, please only use an <a> element if you can answer yes to this question:

1. Does the element change the URL?

If it does not, please use the <button> element. Now for some further explanations:


Why is it so commonplace to use the <a> element to perform JS actions?

The <a> provides some key benefits:

  1. It is styleable.
  2. It is focusable (you could tab to it)
  3. It provides cross-browser support for :hover, :active, & :focus states

Way back in the day, the <button> element only provided the latter two benefits. It was impossible to style it consistently cross-browser (just think of trying to style some of the new HTML5 inputs cross-browser). This has long been remedied. At Ancestry, we created a generic “.link” class to style a <button> exactly like a text link, when needed. This allows us to use the proper HTML markup and retain control of the appearance. The CSS is similar to this:

.link { -webkit-appearance:none; background:none; border:0; -webkit-box-shadow:none; box-shadow:none; color:#03678B; cursor:pointer; display:inline; font-size:inherit; margin:0; padding:0; text-align:left; text-decoration:none; }
.link:active,
.link:hover,
.link:focus { color:#03678B; text-decoration:underline; }

This resets the styles for all our supported browsers and gave us the flexibility we needed in the markup to use the proper <button> element rather than the <a>.

One note about using the <button> element – Don’t leave off the [type="button"] attribute. The default type of a button in most browsers is a submit. This means without the [type="button"] attribute/value pair, users could accidentally submit a form.


What about using the <a> as a named target?

Hyperlinks can link to sections of content in a document, as well as external links. Again, way back in the day, markup like <a name="myRegion"></a> was the only cross-browser way to link to a section on the page. All modern browsers (even back to at least IE7) allow you to link to any section that has the id attribute.

Old way:

<a href="#my-section">Go to my section</a>
...Content...
<a name="my-section"></a>
<div>My section content</div>

Better way:

<a href="#my-section">Go to my section</a>
...Content...
<div id="my-section">My section content</div>

Simply use an id attribute on the containing element of the region you want “linkable.” Don’t use an empty <a name="my-section"></a> element.


Are there any reasons you would bind a JS action to an <a>?

Of course! A common one is a hyperlink that also fires off a tracking pixel. Something like the following:

<a href="http://www.ancestry.com" onclick="fireTracking('clicked home link');">Home</a>

In the case of single page apps, you definitely need to prevent the browser from navigating away from your page, but you should still use an <a> element since the result would be changing the URL. For example:

<script>
function doPushStateStuff(newPage) {
	// pushState magic here
	return false
}</script>
...
<a href="page-2" onclick="doPushStateStuff('page-2');">Page 2</a>

This actually brings up the other key rule for <a> elements:

  1. Users should always be able to open links in a new tab (middle-click or right-click to select “open link in new tab”)

I loathe single page apps that do not allow opening pages in a new tab. It’s a huge usability issue as it prevents users from using your site in their normal routine.


In summary:

  1. Semantic buttons (<button type="button">) should be used when an element’s sole purpose is to perform a JavaScript action.
  2. <a> elements should only be used when changing the page URL and should always be openable in a new tab.
  3. You should never write html like this: <a href="#" onclick="doSomething()">Do Something</a> or this <a href="javascript:void(0);" onclick="doSomething()">Do Something</a>

Note: Use Unobtrusive JavaScript rather than onclick attributes. They simply shortened the examples.

3 Comments

  1. Donya

    How exactly does accessibility suffer if an anchor does not change the URL? My team has been using anchor elements to perform JavaScript actions for years without problems (yet). How will this affect the project in the long run?

  2. Hi Donya, thanks for the question. A couple thoughts come to mind.

    1. It’s important to remember that semantic markup exists so that other tools can properly interpret your page. The <a> element defines an anchor to a new page (or a region on your current page). Even if we couldn’t identify a functional reason to not use one element or the other today, we should still use the semantically correct element because browsers, screen-reading software, or search engine bots could change at anytime to add new behavior or attach new meaning to those elements. If your whole application was built with the wrong element, you’re making your software less “future-proof.”

    2. In a more direct answer to your question, most screen-reader software can bring up a list of links on a page to simplify navigation for non-sighted users. This list of links is put together based off the <a> elements on the page. By using <a> elements solely for JS actions, you’re causing the screen-reader to incorrectly group them with these navigational lists – causing unneeded complexity to non-sighted users.

    3. Along with this issue of mislabeling elements, when a screen-reader is reading a page and comes across an <a> element, it will say “LINK” then the text in the link. The user would then expect activating that link to navigate to a new page. Whereas, a <button> element will be announced as “BUTTON” with its text indicating to the user that a different type of function will be executed.

    4. Using incorrect elements can actually affect the usability for sighted-users as well. Browsers already bind some different behavior on vs <a> elements. If you press SPACEBAR on an <a> element, nothing happens to that element (the page simply scrolls down). If you press SPACEBAR on a <button> though, it will trigger the CLICK event for that element. If a keyboard user navigates to an element that looks like a button, they could press SPACEBAR expecting it to behave like a <button>. By using <a> element though, you’re forcing them to press the ENTER key instead to activate the element. May seem like a little thing, but it’s quite annoying when the page simply scrolls down from the SPACEBAR rather than activating a button.

    Those are just a couple thoughts that come to mind. Hope that helps!

  3. Mike

    I agree with part of your interpretation but you are wrong in assuming the 1:1 relationship between document/resource and address. With the rise of rich clients we are compiling resources that do not sit on a remote server with an ip address. Alot of times, a URL doesnt make sense (eg bookmarking is nonsensical for the current state of the client) and state transitions for these large rich clients simply dont gain anything by shoe-horning old addressing strategies into composed pages. You have multiple concerns going on at the same time in complex rich clients so more innovative approaches must be taken. All that to say that an anchor is semantically linking to a related resource. That isnt necessarily a global state change on the page (eg a new address) but it does represent ‘going’ somewhere but WITHOUT MUTATING STATE. A button, on the other hand, implies DOING something (as you said) and so mutates state…perhaps a simple view attribute or application state. The feeling of ‘going’ somewhere is pretty intuitive…and I agree that it is often wrongly used to change app state where a button is more appropriate.

Comments are closed.