The struggle to help developers how to understand the right HTML to use for visual buttons has been written about over and over. Yet libraries, frameworks, templates, and by extension, sites & applications still continue to get it wrong.

Best Practices

I’m going to quickly recap the correct approach, as generally regarded across the industry by accessibility pros, UXers, and even the specs themselves.

There are exceptions to every rule. I am certain if you think really hard you can come up with one. I bet if you think even harder you can see how that exception applies to you. It doesn’t though. You and your project are not a unique snowflake, a pretty flower that gets a free pass to play in the gray area. You have to justify it well.

It is generally a terrible idea to mix approaches. If you are going to do something incorrectly, you are better off doing it incorrectly in the same way throughout your page / site / application, since users can often adapt. Inconsistency can be confusing and, depending on the purpose of your visual buttons, will reduce the number of users doing the things you want them to do (buy stuff, edit profiles, verify details, etc.).

Does the Control Take Me to Another Page? Use an Anchor

If, when clicked, tapped, or activated by keyboard or voice (or insert novel interaction method here), the user is whisked to another URL (including an anchor on the same page), then use <a href="[URL]">. Make sure you use the href attribute and that it has a real URL, not a “#” (otherwise you’re probably relying on JavaScript, which is not at all necessary for a hyperlink).

Update, January 30: based on comments below I did a poor job here of being specific. If an href points to just a “#”, then you’re probably doing it wrong. If it points to a named anchor as part of your progressive enhancement efforts, then that’s totally valid.

Does the Control Change Something on the Current Page? Use a Button

If, when activated, the user is not moved from the page (or to an anchor within the page), but instead is presented with a new view (message boxes, changes in layout, etc.), then use a <button>. While you could use an <input type="button">, it’s more likely you’ll get into conflicts with pre-existing styles and subsequent developers (like me).

Does the Control Submit Form Fields? Use a Submit

If, when activated, information the user has entered (either by manually typing or by choosing items on the screen) is being sent back to the server, then use an <input type="submit">. This has better live within a <form>. If you need more styling control or have to embed more than just a simple text string, use a <button type="submit"> instead.

Worst Practice

Don’t use a <div>, <span>, or some other non-interactive element. If you cannot tab to it with a keyboard, it’s probably a terrible idea to use. Adding role="button" doesn’t help, that makes it worse.

If you end up with code that looks like this, you are doing it wrong and I would slap you (and no jury would convict): <div onclick="DoThing();" onkeypress="DoThing();" tabindex="0" role="button">Do a thing.</div>

You can see me go into a little more detail on this in my talk for Accessibility Camp NYC, starting at slide 85 or at 25:50 in the video. Dylan Barrel also made a JSFiddle to correct my lack of type="submit" (something I said in the video but corrected in the posted slide 89).

Keyboard

Think of keyboard users for a moment. A hyperlink can be fired by pressing the enter key. But a true button can be fired by pressing the enter key or the space bar. When a hyperlink has focus and the user presses the space bar, the page will scroll one screenful. If there isn’t more to scroll then the user just experiences nothing. Given a set of interface elements that look the same, if some work with a space bar and some don’t, you can’t expect users to have much confidence in how the page behaves.

I think it’s also worth mentioning that events triggered by a space bar only fire when the key is released, whereas using the Enter key will fire the event as soon as you press the key down (prior to releasing it).

If you are using the button to submit a form and your audience uses Internet Explorer 7 or below, then you may have run into the bug where IE submits the innerHTML instead of the value attribute (see last paragraph under Remarks). In that scenario you can use client-side scripting to bypass that bug and/or logic in your server-side processing to still respond accordingly if the JavaScript doesn’t fire properly (progressive enhancement FTW).

Update: May 23, 2016

After spending some of my weekend repeating this a few times on Stack Overflow, I made some tweetable nuggets that you can copy or re-tweet for your own edification.

[0/3] Some general tips on when to use an <a href> versus a <button> or <input type="submit">…#HTML#a11y

And thanks, Thierry, I’ve used the :checked approach before. It’s no JS capability is great, but it bugs me that it is JS dependent on IE7-8 and Android 2.x, and so utterly broken under no JS where :checked is not supported.

After reading @rem’s article last month I’m returning to the anchor pattern.

You are correct, I linked to (and captured) an old version. I pulled it out of my own archives and didn’t check the current release, so that’s on me (and I’ve updated the links and reference above). I see things are far better in the current (6.1.2) release.

I’m curious: why would your first choice be an <input type="submit" /> instead of simply a <button>? The button element’s default type is submit, so to me it seems like it would be better to just use that element for both cases. Other than the IE bug you mentioned, is there a major advantage to using <input type="submit"> instead of <button>?

Nate, there are two reasons I use the <input type="submit"> in that scenario:

The pre-IE8 bug (along with general really-old browser support);

In my experience working with teams, leaning on <input type="submit"> for a <form> and a <button> for a non-form use helps reinforce the purpose of the control with developers. This has had the effect of getting them used to making decisions about client-side scripting, error handling, styles, and so on as their brains are primed for a specific type of interaction belied by the element chosen. Of course, YMMV.

Search iconUsed in the search form as a button.Search iconUsed in the search form as a button.Information iconLower-case 'i' in a circle.Checkmark iconSymbol showing a checkmark.Alert iconExclamation mark within a triangle.