Tabindex, using it right is all about not using it.

We know, tabindex exists for a purpose. But it has its own use. Like every other thing, we tend to over/mis-use tabindex as well. Today the Web has changed, and there are better approaches to handle the use cases that tabindex used to in the past.

I would say that the only place where using tabindex is legitimate is when using −1 as value. −1 is used to make an otherwise not tabbable element tabbable. Best use case for tabindex −1 is for skip_to_links. A skip_to_link is made by setting the href as the id/name of the receiver element. And the element has to have a tabindex −1 to receive the tab. Elements like link(anchor), input fields(form controls) are designed to receive keyboard tab. And for elements that cannot receive tab, we use this method to make it tabbable.
Link:

<a href="#conta11y" id="jmp2Cont"
    onclick="jQuery('.cont').focus()"
    title="Jump to Content">Jump to Content</a>
Land at:

<a href="" id="conta11y" tabindex="-1" title=""></a>
For everything else tabindex is evil.
You can use skip-to links, but html5 has come with semantic elements like <header> and <footer>. Assistive Technology (AT) understands these objects as landmarks and provided option to jump to them directly. This way also helps user to jump to content easily as soon as the page loads, than having to navigate through many navbar links to reach the main content.
ARIA (Accessible Rich Internet Applications Suite) can be used for the same. If role=“main” is added, AT will understand  that this is the most important part of the page.
So, now we have an alternative for skip-to links as well. Let’s not use Tabindex.
The bad sides of using Tabindex are listed below. They are about development practices and code quality.
  • Code becomes hard to maintain.
  • For minor additions, we will have to do extensive tabindex changes, like adding tabindex values towards the next tabbable elements.
  • We are achieving some functionality by addition of a new attribute tabindex, when we can achieve the same by (probably) reducing the number of unwanted HTML elements (like excess DIVs used) and by using proper HTML semantics.
The HTML itself has to be constructed in such a way that it is semantically meaningful.
The best way to make sure the HTML we wrote is semantic, is to represent it as a tree. Then see which all elements are placed at what level in the tree. If the order in the tree is not even, then it is a sign that our HTML is not semantically correct.
This also helps to reduce unwanted HTML elements. We tend to write a lot of DIVs only to use with CSS. This is a smell. We should reduce the DIVs and utilize CSS to the maximum to layout the page as we want.
Use proper elements like UL-LI, H1, H2, H3, P etc to define content, instead of using DIVs.
There are cases where people uses DIVs for lists. Certain plugins also do the same, making things out of the way.
There are people who write a lot of DIVs to show a list of buttons. Say, for showing a list of tabs, navigations etc. The only proper way to display it is to show it in UL-LI lists or OL-LI as required. Even people who use LI, add a DIV within the LI, which is an overloaded use of div.
</pre>
</div>
<div>
<pre><ul>
  <li>
    <div>Wrong way of doing it!</div>
  </li>
</ul>
We don’t need an extra DIV there. If we need to add any styles, we can add it on the LI itself. Just make sure you select the element using a class name, than using the element itself, in the style sheet.
CODE:
</pre>
</div>
<div>
<pre><li class=“list”>Content</li>

<style type=“text/stylesheet”>
  .list { color: blue; }
</style>
is preferred over
</div>
<div>
<pre><style type=“text/stylesheet”>
  li.list { color: blue; }
</style>
This makes the code independent of elements and a change at a later point becomes easier. As an Accessibility POC for my company, I prefer this approach as that makes my job of making the elements HTML standards compliant easier. This method reduces my job, at least at the CSS level as fewer things are prone to break in this approach.

Thoughts ?

Thanks to @unnitallman (Unnikrishnan KP) who took out his time to proof read this article.