Links are not buttons! -- article by Karl Groves

The basics are this (with notes added by me):

  • you get automatic semantics and accessibility using the right element for the job.

  • if you don’t (and use something like a div or span for a button) you need to manually add in all the accessibility and functionality yourself.

  • links are clicked and activated with ENTER or single tap. They take you somewhere.

  • buttons are clicked and activated with SPACEBAR or ENTER or often double-tap (this is why single taps on buttons are sometimes slow… browser is waiting to see if the tap is really a double tap. You can get around this by using touchEnd events instead of click events for your mobile pages). They usually Do Stuff rather than take you somewhere.

I’m guilty of using links to Do Stuff, quite regularly.

[noparse]<a class=“btn”></a>[/noparse]
If an anchor doesn’t have an href attribute, it may not be focusable (I know addThis twitter buttons didn’t work in any version of IE I tested in with keyboard, solely due to lack of href). AT doesn’t see anything focusable or clickable there either. It does not exist as far as they’re concerned.

[noparse]<a href=“#”></a>[/noparse]
If an anchor is empty and you’re using a background image to show the clickable thing and its text, this can and will vanish when users have High-Contrast settings in their browser (Microsoft has a possible CSS option for reversed icons here and I only know of the High-Contrast issue on Windows but if images vanish anywhere else then this also can’t be a complete solution).

The above link will also take users to the top of the page. Disturbing someone’s focus even if visually nothing changes is a pain in the butt.

-------------------------MOAR NOTES---------------------------------
I’ve been using a non-existing hash for these: <a href=“#void”>link focus goes nowhere when clicked</a>. Still, I should be using a <button>.

If you’re forced to deal with spans or divs as buttons, like trying to fix someone’s jQuery plugin, you need to do at least all this:

<span role=“button” tabindex=“0”>FAKE BUTTON</span>
Role of button gives it a role to browsers and AT. Tabindex makes it natively focusable without screwing with native tab order (don’t set to a number larger than 1). Even so, now you can focus on it but can’t activate it.

In your Javascript onclick method you need to add an onkeyup or onkeypress or whatever your favourite is and test for ENTER and SPACEBAR.
Here’s a chunk I did for a jQuery plugin our company uses but by default only works with the mouse:


var resetbtn = item.find('.rateit-reset');
    if (stuff is true...) {
        resetbtn.click(function () {
            //does stuff onClick;
        });

    [b]//is role=button, but not natively clickable
        resetbtn.keyup(function(e) {
            var code = e.which;
            if ((code === 13) || (code === 32)) {
                $(this).click();
            }   
        }); [/b]
    }

Stommey!!

Nice article, but it kinda and odd issue.

For example, I have been developing a CMS/templating system( essentially, my own idea of WP). I have coded some control modules to control entries and pages. ( think of them as the dashboard), so for the sake of example I have the following modules

*add entry
*delete entry
*edit entry

Add entry is self explanatory
The delete entry is just <SELECT> of all the entry IDs is the DB, the FORM action goes back to itself( the same document) and deletes all the IDs passed in the query string
Edit entry is also a <SELECT> but this time the PHP redirects to add entry , with the ID of the entry added to the query string, which tells the script in the add page to fill the form with the data from the DB corresponding to the ID in the query string.

BUT as a nice UI touch, you can delete the entry you are working on from the edit entry module. That is a ‘delete this entry’ “button” is added to the form. Actually it’s a link. I pain painstakingly styled to look like a button, conceptually: <a href=“deleteEntry.php?id=”.$_GET[‘id’].">Delete this entry</a>

Coding this as button would have required:

  1. js to alter the default action of the form ( Entry.php)
  2. making it’s own separate form, with the deleteEntry.php?id=xx as its action
  3. adding a delete single routine AND code to check that the form was submitted via the delete button

All viable, but not as graceful than just heading straight to deleteEntry.php. Thus it’s a case where this both a BUTTON and a link; when the data from one form can grafuly integrate to the processor of another ( submitting and redirecting in one action, w/o any extra php/js)

I did consider that screen readers read it as a LINK and not a button/input like the rest of the form control, but since the context is so direct “delete THIS document” it hardly seems confusing. Leaving only the FOCUS consideration, then again this is beneficial as I don want someone accidentally deleting something by pressing tab/return too quickly .

Touching on attributes, since I only wanted the ID to be passed, then essentially the attributes are written directly into the query string.

I guess what I am saying is that there are SOME legitimate (albeit rare)GRAY areas, in which a link can be a button and vice versa.

It sounds like a problem I’ve run into where there’s basically one form holding information, but users need two separate choices for it. Your hacky-solution-#1 is pretty much what I did then too. However I didn’t have anything to help me on the front: no templates grabbing information from the backend to get id’s and things. I have that now and it’s very nice.

But <button>s don’t have to have anything to do with forms. Push buttons just have a specific UI: how they are activated and what their meaning is.

<a href=“deleteEntry.php?id=”.$_GET[‘id’].“>Delete this entry</a> basically is avoiding an onclick handler?
<button data-url=“deleteEntry.php?id=”.$_GET[‘id’].”>Delete this entry</button> + onclick.

But it’s a GET request? And when a user deletes something they are shown some sign of success (such as an empty form page or back to a list of options)? You could probably call that GoingSomewhere (like a POST/REQUEST/GET) and therefore a link :slight_smile:
(it would be cool if your anchor could send an actual DELETE request instead of GET… that would be lawlz).

I was looking here and [url=http://www.w3.org/TR/wai-aria/roles#link]here to see what’s possible but it’s pretty much the same as Groves’ article.

Ah, Dresden, you may also be talking about something I’ve missed, that some UA’s apparently think any <buttons> within a <form> are submits… I haven’t seen this (I don’t use <button> enough) but it’s mentioned here (which you’ll prolly be interested in, too):

But it’s a GET request? And when a user deletes something they are shown some sign of success (such as an empty form page or back to a list of options)? You could probably call that GoingSomewhere (like a POST/REQUEST/GET) and therefore a link :slight_smile:
(it would be cool if your anchor could send an actual DELETE request instead of GET… that would be lawlz).

actually, since it was my attempt at reinventing the wheel, and fire and sliced bread… yeah I bet I did a lot of unorthodox things :wink:

document ‘polymorphism’ was actually the key here. there are two php documents perform 5 modular functions depending what the POST/GET input is. A GET value that is missing from the DB, simply outputs a message that the data is not available. Since, as a courtesy, the delete document reads the ‘name’ of what its deleting ( so it can say "so and so’ was deleted… it too intelligently responds to failed DB deletions), I am not to concerned about security, as all module redirect to a log in page, if no session is present.

targeting a db record via a combination of GET/POST actually adds functionality ( i used to do it with WP… go t fed up of the dashboard and just typed the URL?ID=xx).

The article is interesting ( as is the …UGH jquery… plug in)… but now I am confused would that plug in make it more likely people use links as buttons and buttons as links?

I often explain accessible by saying “code what you mean” ( as opposed to how it looks or functions)

so my question after all this would be… when is something a link and when is it a button?
in my humble know how … I would say a link leads you to another document, and a button instantiates an event.

oh… worse yet, it has become common place (thanks again WP) that clicking on the heading link leads you to that SINGULAR document page, and not reveal some more content int the current page. I am ambivalent about the functionality of "drop down activating headings) as they may initially confuse users. Yes I know this could also become the new norm… but there will be a period of pain)

The good old link vs button debate popped up on WebAIM a few months ago, and every so often: http://webaim.org/search/?scope=archives&q=link+button
.