DevYarns

How to Know Whether to Use a Button or a Link for Accessibility

October 15, 2020

When we write JavaScript applications and we’re adding click event listeners all over the place, it can be hard to know which element is the most semantic and accessible choice for the job!

Often, the decision comes down to “should this be a link or a button?” Or maybe, God forbid, a div?

Generally, it’s not a good idea to build an interactive element out of a div. You’ll have to do extra work to make sure it’s accessible to keyboard and screen-reader users.

A common question I see around this is, “but what about cards? How do I make a card without a clickable div?” Here is a great resource from Heydon Pickering on building accessible cards.

In 99.9% of cases, a clickable div is not the solution, but a link or a button probably is. So, how to decide?

In This Article:

  1. Why this matters.
  2. When to use a link.
  3. When to use a button.
  4. What if marketing/business/design says it has to be a link?
  5. Further reading.

Why This Matters

The problem with using a link when you should use a button, or the other way around, lies primarily with the confusion it can cause screen reader users.

When a screen reader user wants to find a specific link, they might pull up a list of links and not find what they are looking for because you used a button instead. Or, they might find something in the list of links that behaves like a button, causing confusion and frustration.

When to Use a Link

The intended purpose of a link is to take a user to a different location. If an element’s main purpose is to take someone to a new page, or to a different location on the same page, that element should be a link.

There may be cases where a button has a side effect of sending a user to a different location on the page, but that is not its main purpose. In this case, a button may be more appropriate.

For everything else, use a button!

When to Use a Button

Buttons have two main purposes: activating some functionality, or submitting a form.

Some examples of functionality a button might activate include hiding/showing something, popping up a dialog, or expanding a collapsed menu.

Button Types / But What Kind of Button?

There are three types of HTML buttons. Choosing the right type is another key element of making your app’s interactive features accessible.

1. The Submit Button

Setting your button’s type attribute to submit creates a button that submits form data by default. This is also the default type for buttons inside <form> elements that don’t have a type specified.

The markup for a submit button looks like this:

<button type="submit">Submit</button>
Event Listeners for Submit Buttons

For buttons that submit forms, it is best to use a submit event listener on the form itself, NOT on the button. That will allow users to submit the form with their enter key.

In the following sample markup, notice that there is no event listener on the button at all:

<form onsubmit="handleSubmit()">
  <label for="first-name">First Name: </label>
  <input type="text" id="first-name" />

  <button type="submit">Submit</button>
</form>

2. The Reset Button

When a button with its type set to reset is placed inside a <form> element, it will reset all values in a form to their initial values. This is its default behavior without any event handlers specified.

Think very carefully before including a reset button in your form. It will be pretty easy for your users to accidentally click one and lose all their data when they were trying to submit.

3. The Button Button

When your button does not submit or reset a form, use a button with its type attribute set to button. The button type has no default behavior associated with it, making it a perfect blank slate to trigger functionality when it is the target of events.

I know it might seem silly or redundant to specify type="button", but this helps make sure your button won’t try to submit (nonexistent) form data and look for a (nonexistent) response. The default behavior of a button without a type specified is to try to submit data!

The markup for a button that activates some functionality when a user clicks it, without submitting a form, might look something like this (where handleClick is a function you define to do something when the button is clicked):

<button type="button" onclick="handleClick()">Perform some action</button>
Sidenote: Why Use a Click Event

Screen reader users should be able to activate a button using their enter or space keys, plus your events should also work for users with touch devices, like smartphones.

Click event listeners are the ultimate device-independent event listener in this regard. A click event is fired on click, touch, space, AND enter, so using onclick with a button will have you covered.

What if Marketing/Business/Design Says it Has to be a Link?

So, you know your element should be a button, but the marketing team in your office is insisting that it has to look like a link?

That’s okay! You can and still should use a button. You can apply some CSS to make it look like a link and everyone should be happy.

Here is the general approach I would take:

  1. Add a class to your button in the markup.
  2. Select that class in the CSS and style it to remove the background color, border, and padding, apply your link styles, and set the cursor to pointer since users expect to see that cursor when they click a link.
  3. Add some hover styles to match the links in your layout.

Take this button as an example:

This button might have the following markup:

<button type="button" class="btn--link">Fake Link</button>

I could apply these styles to it:

button.btn--link {
  /* remove button styles */
  border: none;
  background: none;
  padding: 0;

  /* add link styles */
  cursor: pointer;
  color: blue;
  text-decoration: underline;
}

button.btn--link:hover {
  text-decoration: none;
}

And create a button that looks like a link, like so:

Further Reading

The MDN documentation on the button element has a lot more information on the various other possible attributes beyond type and discusses additional accessibility concerns.

This post on the Deque blog about building accessible buttons with ARIA discusses what you can do if you can’t use the native button element for some reason, such as needing to retrofit existing code that uses other elements. There are a significant number of concerns you will have to address if you can’t use a real button, so I still highly recommend using a button (when you don’t need a link) whenever possible.


Rachel Leggett, is an Ann Arbor-based front-end web developer, accessibility specialist, and knitwear designer. She spins some yarns about web development, web accessibility, and other tech topics in the DevYarns blog.

© Rachel Leggett, Built with Gatsby