Setting tabindex in HTML for arbitrary, disparate elements

I hit upon a picky need by a user to have specific tab-order for a HTML page. For most part we usually would organize the layout itself to allow for default left to right, top to bottom tabbing of elements. Or we could always explicitly set tabindex to specific order.

Trouble was, having limited capability to influence the HTML generated by the package, the only option was do some post UI alteration using JS, or CSS only. Not surprisingly, CSS is about formatting, not navigation hence there isn’t any CSS property for tabindexes. The only option in hand was JS, so I was playing with a couple of approaches to look at the problem

  • Request user to live with the default tab order – Not an option :-)
  • Use CSS – Not possible to set navigational properties such as tabindex
  • Use JS
  • Hack onfocus, onblur to attach/de-attach custom tabindex – didn’t work for set of controls, since one can enter any control using mouse, still custom tab order needs to be maintained. Another issue was controls appearing after custom tabindexed controls didn’t get any focus any more.
  • Use onkeyup, onkeydown events, detect TAB – didn’t work because onkeydown, onblur occurred on element having focus, then onfocus, keyup occurred on element receiving focus. While logically correct, my sample code quickly became a mess of booleans tracking keyup and tab key, then clearing it onfocus, but again similar to previous issue this didn’t work either.
  • From a completely different perspective, surround required elements in containers, like div, span or fieldset. This would automatically take care of tab order, but trouble is the elements I had to work on were in table row cells, and HTML doesn’t allow interleaving of containers (which is logical).
  • Had to work simply across all browsers without differences in implementation. I came across some posts suggesting setting required tab order through java script for all known elements. Another post improved this thought by suggesting to have tabindexes with incremental gaps say 10, so that additional elements could be put in tabindex later on.
  • So my final working approach took both of the above, and mistakes in approach to come up with a very simple solution as below
    <script type="text/javascript" language="javascript" src="prototype-1.7.min.js"></script>
    <script type="text/javascript" language="javascript">
    //<![CDATA[<!--
    // Requires prototype.js
    document.observe("dom:loaded", function() {
    /* Specify elements in order of required tab index, cte= custom tab elements */
    var cte= $('select7', 'select9', 'select10', 'searchkb', 'select8');
    /*
    * Logic to set custom tabindexes for elements
    * First set tabindexes for all known input-able elements in with gaps in between
    * For required elements, set tabindex in that gap range
    */
    var idx= parseInt(1000), incr= parseInt(10); // Begin with any suitable base number, idx= index, incr= suitable increment gap to allow assigning tabindexes in sequence
    $$('input', 'select', 'option', 'textarea').each(function(el) { try { el.writeAttribute('tabindex', idx+=10); } catch(err) { void(0); } });
    var fi= parseInt(cte[0].readAttribute('tabindex')); // fi= tabindex of first element
    cte.each(function (el) { el.writeAttribute('tabindex', fi+=1); }); // Rest of the elements receive sequential tabindex
    });
    //-->]]>
    </script>

I was leaning on using jQuery’s attr to write tabindex, but for some reason (I know that’s not an excuse) it didn’t work. Perhaps it should, however prototype’s writeAttribute, readAttribute worked, so I ended up using that. Also note that not all elements support tabindex,  though I’ve limited to input-able elements, so setting this throws error which I’ve deftly gobbled up; not a good practice but if someone knows an elegant way to find if element supports some property that would be great. On other hand, I would prefer jQuery, or prototype hiding such intricacies behind their APIs instead of me having to do it since it’s javascript anyways. The try, catch could be altogether removed though.

BTW, I used YUI’s excellent javascript compressor to minify prototype’s javascript. Google’s CDN didn’t provide a minified prototype.js, I wonder why …?

I believe my goal of having a simple, yet elegant way to override tabindex, taborder especially if you have no control over HTML was achieved. Perhaps this helps you in some way as well.

2 thoughts on “Setting tabindex in HTML for arbitrary, disparate elements”

  1. Excellent information however I’d like to let you know that I think there is problem with your RSS feeds as they seem to not be working for me. May be just me but I thought overall I would cite it.

Have something to say?