Karl Groves

Tech Accessibility Consultant
  • Web
  • Mobile
  • Software
  • Hardware
  • Policy
+1 443.875.7343

Links are not buttons. Neither are DIVs and SPANs

Quick: what is this?

pseudo button

If the word “Button” comes to mind, you might be right. Unfortunately we’ve been seeing a lot of instances in our testing where an image or CSS styling is used to trigger an action of some kind. Here are some markup samples:

<a href="#"><img src="path/to/image.gif" /></a>

<span class="btn_addnew"></span>

<a class="btn_addnew"></a>

<a href="javascript:myFunc();"><img src="path/to/image.gif" /></a>

BUTTON considerations

In each of the cases listed above, the markup is inappropriate and creates unneeded accessibility problems. In the case of buttons, we need to keep in mind the following accessibility considerations:

  1. Device independence: Users must not be required to use any specific device to operate the control. In other words, users must be able to gain focus on it and activate it using a keyboard or voice commands as well as a mouse
  2. Color Contrast: The design of the button must have sufficient color contrast, and the button must not disappear in high contrast mode.
  3. Name, State, Role, Value: The button must properly expose itself to accessibility APIs using the appropriate Name, State, Role, and Value for what the object is. As I’ve described in another blog post:
    1. Name – Similar to a person’s unique name, what is the name of this thing?
    2. State – What is this thing doing? Implicitly, what else can it do?
    3. Role – What type of object is this thing?
    4. Value – What value does this thing have? (Typically only form elements have a value)

DIVs and SPANs are not buttons

The first thing to be aware of is that a SPAN should never be used as a button. “Elements that only expose the HTML core attributes are represented by the base HTMLElement interface.”

interface HTMLElement : Element {            
    attribute DOMString       id;            
    attribute DOMString       title;            
    attribute DOMString       lang;            
    attribute DOMString       dir;            
    attribute DOMString       className; 

Furthermore, you should never use a DIV, either. Its DOM interface is the same as a SPAN except that it adds one new attribute, ‘align’, which is deprecated.

interface HTMLDivElement : HTMLElement {            
    attribute DOMString       align; 

Here, however, is the DOM Interface for a BUTTON element:

interface HTMLButtonElement : HTMLElement {   
    readonly attribute HTMLFormElement form;            
    attribute DOMString       accessKey;            
    attribute boolean         disabled;            
    attribute DOMString       name;            
    attribute long            tabIndex;   
    readonly attribute DOMString       type;            
    attribute DOMString       value; 

and here is the interface for the A element:

interface HTMLAnchorElement : HTMLElement {            
    attribute DOMString       accessKey;            
    attribute DOMString       charset;            
    attribute DOMString       coords;            
    attribute DOMString       href;            
    attribute DOMString       hreflang;            
    attribute DOMString       name;            
    attribute DOMString       rel;            
    attribute DOMString       rev;            
    attribute DOMString       shape;            
    attribute long            tabIndex;            
    attribute DOMString       target;            
    attribute DOMString       type;   
    void               blur();   
    void               focus(); 

(The above DOM interface descriptions come from: http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html)

You should notice a few very important new attributes: ‘tabIndex’, ‘accessKey’, and in the case of BUTTON, ‘value’. We’ll skip over discussion of the accessKey property other than to mention that according to the HTML specification, items for which the accesskey and tabindex attributes are valid are links, buttons, and form fields. In other words: items that are natively available in the tab order and therefore able to be accessed in a device-independent manner. You’ll notice no such properties for DIV or SPAN.

Using our list of considerations above, let’s compare DIV & SPAN against A & BUTTON

Requirement DIV & SPAN A & BUTTON
Natively keyboard accessible No Yes (for A, only when href present)
Sufficient Color Contrast Design Dependent Design Dependent (unless using native BUTTON with no CSS)
Exposes appropriate name, state, role, value No Yes

Some readers may note that you can manipulate Name, State, Role, and Value on DIVs and SPANs using WAI-ARIA. The authors of the WAI-ARIA spec say: It is not appropriate to create objects with style and script when the host language provides a semantic element for that type of objects (source). A button is clearly one of those things where a semantic element exists. WAI-ARIA is best reserved for those cases where there’s no other way to accomplish your goals. In other words, WAI-ARIA is great for tri-state checkboxes and date pickers, but just plain silly for buttons. In short, DIVs and SPANs aren’t buttons (or links, for that matter) no matter what you do. If you use them, you are wrong.

How to choose between a link and a button

Now we’re left with links and buttons. How do we choose between the two? Quite simply, by answering one question: What will happen when the user activates this control? The Microsoft User Interface Interaction Guidelines discussions of buttons and links outline this decision-making process rather well (paraphrased here):

  1. Will this control be used to initiate an immediate action?
  2. Is the action to navigate to another page?

Elsewhere they outline some general guidelines on making the choice:

  • Use command buttons for:
    • Primary commands.
    • Displaying windows used to gather input or making choices, even if they are secondary commands.
    • Destructive or irreversible actions, as well as commitment within wizards and page flows.
  • Use links for navigation to another page, window, or Help topic; display definitions; and command menus.

Whether or not you’re a Windows, Mac, or Linux person, these UI paradigms are the de-facto standard for link and button controls across all operating systems.

  • A button initiates an immediate action, such as form submission.
  • A link triggers navigation to a different resource.

A link with a crappy (or missing) href isn’t a button

I must see things like these at least once a day:

1. <a class="btn_addnew"></a>
2. <a href="#"><img src="path/to/image.gif" /></a>
3. <a href="#"></a>
4. <a href="#">Some button text</a>

In first case, I often see these with background image sprites that give the control the visual look of a button. In this case this item is neither a button or a link. Because this item lacks an href attribute, it is an “anchor”, not a link. As an anchor it is not keyboard focusable. Furthermore, due to the use of a background image sprite, the item has no text alternative for the image and therefore no ‘name’. For low-vision users in High Contrast Mode, the image will disappear. For voice dictation users, they will be unable to use link or button commands on that control. From an accessibility standpoint, this item may as well not exist at all and the use of A here is no better than SPAN.

The second example is being seen less and less these days, superseded as it were, by some variations of 3 or 4. In each of these cases, these objects are only marginally better than the first example. In the first example, the lack of an href attribute meant that the item can’t get focus via keyboard. In these examples we see the use of ‘href=”#”’. Developers often use the hash mark to have a link that (they think) does nothing. The problem is that they’re wrong in multiple ways.

Per the specification, the ‘#’ is a “Fragment Identifier Separator”. In other words, the “#” is meant to precede a string of text which identifies a fragment on the page – a named anchor or an object’s specific ID. Developers think that by having no identifier it points to nothing, and unfortunately they’re 100% right. In certain browser/ operating system combinations, this may also mean that focus is shifted elsewhere. In some cases, for instance, it has the apparent effect of pointing to the browser window or body element. From there the tab order re-starts from the beginning.

Imagine this scenario: you’ve programmed a pseudo button which navigates through a wizard-like process with multiple steps, each using that <a href=”#”> link. Each time a keyboard user completes one step, they need to start over at the very top of the page, tabbing through to the next step. Lame.

Perhaps the thing that confounds me the most about using links (or spans or divs) as buttons is that there’s no intelligent argument that can be made in favor of this practice. The BUTTON element can be styled just like links, divs, and spans and no matter which of these elements you choose you still need to bind the relevant events to your control. So if it looks like a button and acts like a button, what compelling reason is there to not just use a button?


  1. DIVs and SPANs are not buttons
  2. If it navigates, it is a link. Use link markup with a valid hypertext reference
  3. If it triggers an action, it is a button. Use a BUTTON element
  4. If you don’t like how a button looks, style it with CSS.
I’m available for accessibility consulting, audits, VPATs, training, and accessible web development, email me directly at karl@karlgroves.com or call me at +1 443-875-7343