Three Reasons to use HTML5 native button element

When you use alternate elements as buttons, you forfeit a lot of built in functionality which you then have to replicate with custom code. This custom code can add a lot of time to a project and should be avoided whenever possible. There are many reasons to use button elements rather than styling a non button element to look like a button. Out of all of the reasons, the following three reasons resonate with me the most.

  1. Automatic tab indexing
  2. Space bar and enter key activates the click handler
  3. Disabled state

Initial State 

If you place a button element on a page it will receive focus and can be tabbed through in the order they are placed on the screen. Take a look at this plunk which has three buttons that look identical and are all clickable. If we look at the source for these 3 buttons it’s clear that only the third button is actually using a button element. The first one is a div and the second is a hyperlink. After clicking the third button click "shift + tab" to navigate to button 2 and you will see that button 2 does not receive focus.

<div class="myButton" (click)="clickHandler('div')">Button 1 </div>
<a class="myButton" (click)="clickHandler('anchor tag')">Button 2</a>
<button type="button" class="myButton" (click)="clickHandler('button')">Button 3</button>

Workaround: Adding Tab Stops

We can ensure that each button can receive focus by assigning it a tabindex.

<div tabindex="1" class="myButton" (click)="clickHandler('div')">Button 1 </div>
<a tabindex="2" class="myButton" (click)="clickHandler('anchor tag')">Button 2</a>
<button type="button" class="myButton" (click)="clickHandler('button')">Button 3</button>

This plunk has the tabindexes set and each button can be accessed via tabbing. One thing to note is that when button 1 and button 2 have focus and you press the space bar or enter key nothing happens. In order to get the same functionality as button 3 we would have to write custom code that listens for keyboard events and determine which key was pressed and invoke the click handler if the keycode matches the space or enter keys. 

Workaround: Showing Disabled State 

Another drawback of not using the button tag is having to handle the disabled state.

<div disabled tabindex="1" class="myButton" (click)="clickHandler('div')" >Button 1 </div>
<a disabled tabindex="2" class="myButton" disabled (click)="clickHandler('anchor tag')">Button 2</a>
<button type="button" disabled class="myButton" (click)="clickHandler('button')">Button 3</button>

All three buttons on this plunk appear to be disabled. Click on Button 3 and nothing happens, however Button1 and Button 2 can still receive focus and be clicked. In order to achieve the same functionality you would have to write more custom code which adds unnecessary scope to the project.  

I have shown 3 reasons of the many but I think it's clear that this is a lot of extra work to do with no real benefits and should be avoided whenever possible. If you need a button to work like a button than use button.  The entire button spec can be viewed here.