I have a form with many fields and I have given every single input, select and button a tabindex number. That works, but I'd like to do it programatically.
The default tabindex order isn't correct because i have a two-column layout with groups in each column. I want to go top-down by group. How can I write a body.onload function so that it would assign all input, select and button tags a tabindex number based upon the containing div? For example, for the div I want to be cycled through first, all the input, select and button tags could have a tabindex=1
, and all the input, select and button tags in the second div could have tabindex=2
, and so on.
Thanks!
Here's a simplified example
<style>
.a { display: inline-block;
width:200px;
border: 1px solid black;
}
</style>
<div class="a">
<div id="Div01" title="these inputs should have tabindex=1">
<p>Div 01</p>
<input id="Div01Field1" type="text" value="Me first"/>
<input id="Div01Field3" type="text" value="Me second"/>
<input id="Div01Field2" type="text" value="Me third"/>
<hr>
</div>
<div id="Div03" title="these inputs should have tabindex=3">
<p>Div 03</p>
<input id="Div03Field1" type="text" value="Me seventh"/>
<input id="Div03Field2" type="text" value="Me eighth"/>
<input id="Div03Field3" type="text" value="Me ninth"/>
<hr>
</div>
<div id="Div05" title="these inputs should have tabindex=5">
<p>Div 05</p>
<input id="Div05Field1" type="text" value="Me thirteenth"/>
<input id="Div05Field2" type="text" value="Me fourteenth"/>
<input id="Div05Field3" type="text" value="Me fifteenth"/>
</div>
</div>
<div class="a">
<div id="Div02" title="these inputs should have tabindex=2">
<p>Div 02</p>
<input id="Div02Field1" type="text" value="Me fourth"/>
<input id="Div02Field2" type="text" value="Me fifth"/>
<input id="Div02Field3" type="text" value="Me sixth"/>
<hr>
</div>
<div id="Div04" title="these inputs should have tabindex=4">
<p>Div 04</p>
<input id="Div04Field1" type="text" value="Me tenth"/>
<input id="Div04Field2" type="text" value="Me eleventh"/>
<input id="Div04Field3" type="text" value="Me twelfth"/>
<hr>
</div>
<div id="Div06" title="these inputs should have tabindex=6">
<p>Div 06</p>
<input id="Div06Field1" type="text" value="Me sixteenth"/>
<input id="Div06Field2" type="text" value="Me seventeenth"/>
<input id="Div06Field3" type="text" value="Me eighteenth"/>
</div>
</div>
I have a form with many fields and I have given every single input, select and button a tabindex number. That works, but I'd like to do it programatically.
The default tabindex order isn't correct because i have a two-column layout with groups in each column. I want to go top-down by group. How can I write a body.onload function so that it would assign all input, select and button tags a tabindex number based upon the containing div? For example, for the div I want to be cycled through first, all the input, select and button tags could have a tabindex=1
, and all the input, select and button tags in the second div could have tabindex=2
, and so on.
Thanks!
Here's a simplified example
<style>
.a { display: inline-block;
width:200px;
border: 1px solid black;
}
</style>
<div class="a">
<div id="Div01" title="these inputs should have tabindex=1">
<p>Div 01</p>
<input id="Div01Field1" type="text" value="Me first"/>
<input id="Div01Field3" type="text" value="Me second"/>
<input id="Div01Field2" type="text" value="Me third"/>
<hr>
</div>
<div id="Div03" title="these inputs should have tabindex=3">
<p>Div 03</p>
<input id="Div03Field1" type="text" value="Me seventh"/>
<input id="Div03Field2" type="text" value="Me eighth"/>
<input id="Div03Field3" type="text" value="Me ninth"/>
<hr>
</div>
<div id="Div05" title="these inputs should have tabindex=5">
<p>Div 05</p>
<input id="Div05Field1" type="text" value="Me thirteenth"/>
<input id="Div05Field2" type="text" value="Me fourteenth"/>
<input id="Div05Field3" type="text" value="Me fifteenth"/>
</div>
</div>
<div class="a">
<div id="Div02" title="these inputs should have tabindex=2">
<p>Div 02</p>
<input id="Div02Field1" type="text" value="Me fourth"/>
<input id="Div02Field2" type="text" value="Me fifth"/>
<input id="Div02Field3" type="text" value="Me sixth"/>
<hr>
</div>
<div id="Div04" title="these inputs should have tabindex=4">
<p>Div 04</p>
<input id="Div04Field1" type="text" value="Me tenth"/>
<input id="Div04Field2" type="text" value="Me eleventh"/>
<input id="Div04Field3" type="text" value="Me twelfth"/>
<hr>
</div>
<div id="Div06" title="these inputs should have tabindex=6">
<p>Div 06</p>
<input id="Div06Field1" type="text" value="Me sixteenth"/>
<input id="Div06Field2" type="text" value="Me seventeenth"/>
<input id="Div06Field3" type="text" value="Me eighteenth"/>
</div>
</div>
Share
Improve this question
edited Nov 30, 2011 at 2:38
Michael Swarts
asked Nov 27, 2011 at 0:42
Michael SwartsMichael Swarts
3,9218 gold badges36 silver badges46 bronze badges
8
- 1 This might help: stackoverflow./questions/3059203/tab-index-on-div – Sudhir Bastakoti Commented Nov 27, 2011 at 0:56
- I'd prefer a straight JavaScript function to a jquery solution. But yes, essentially that's the right idea. Because divs cannot be tab-indexed the way I had imagined, I need to apply tabindex numbers to elements based upon which div they are contained in, and set a div order that the function would follow. – Michael Swarts Commented Nov 27, 2011 at 1:01
-
tabindex=0
doesn't work the way you describe. From the WCAG 2.0 techniques: When the interactive elements are navigated using the tab key, the elements are given focus in increasing order of the value of their tabindex attribute. Elements that have a tabindex value higher than zero will receive focus before elements without a tabindex or a tabindex of 0. – steveax Commented Nov 27, 2011 at 2:27 - Thanks Steveax – I did not know that! But the goal is the same, just starting from 1... :) – Michael Swarts Commented Nov 27, 2011 at 3:02
- It would be helpful to see the HTML markup. Maybe create a simplified fiddle? – steveax Commented Nov 27, 2011 at 3:44
4 Answers
Reset to default 6 +50A more flexible version of Mike's code which sets the tabIndex to the number used in the Div id's. This also needs no modification when you change the page structure.
Any div with no id or with an id which does not match the prefix-number pattern is ignored.
<script> "use strict"; // place after </body> tag
(function TabNumbers (pfx) {
/* For all divs in the document with an id pfx followed by a number,
set the tabIndex of all immediate children with tags of INPUT,
SELECT, or BUTTON to the numeric value */
pfx = new RegExp ('^' + pfx + '(\\d+)$');
for (var divs = document.getElementsByTagName ('div'),
el, m, i = divs.length; i--;) { // traverse all divs
if ((m = divs[i].id.match (pfx))) { // for those with id Div#
for (el = divs[i].firstChild; el;
el = el.nextSibling) { // Traverse their child nodes
if (el.tagName === 'INPUT' || el.tagName === 'SELECT' ||
el.tagName === 'BUTTON') {
el.tabIndex = +m[1];
}
}
}
}
}) ('Div');
</script>
After some discussion the spec was modified and the following code was accepted :
<script> "use strict"; // place after </body> tag
(function TabNumbers () {
var itags = ["INPUT", "SELECT", "BUTTON"]
, tags
, tag
, el
, t
, a
;
while (itags.length) {
for (tags = document.getElementsByTagName (itags.pop ()), t = tags.length; t--;) {
el = tag = tags[t];
while ((el = el.parentNode) && el.tagName) {
if (el.getAttribute && (a = el.getAttribute ('data-tindex'))) {
tag.tabIndex = a;
break;
}
}
}
}
}) ();
</script>
Tested on Chrome
If the containers Div01
etc can have sortable ids like in your example then you can do this
jquery solution
var groups = $('div[id^="Div"]').sort(function(a,b){
return (a.id > b.id) ? 1 : -1;
});
groups.find(':input').each(function(idx){
$(this).prop('tabindex', idx+1);
});
Demo at http://jsfiddle/gaby/sNekS/
Alternatively (and likely more correctly) you can just rearrange your divs so that they are correctly sorted in the source and still show in left/right groups when rendered (using float:left
on the inner divs), and use no scripting at all..
Demo at http://jsfiddle/gaby/sNekS/1/
Vanilla Javascript solution (after adding class group
to the Div##
elements and class input
to the input/select/etc elements)
var gnodes = document.getElementsByClassName('group'); // find elements with group class - non-sortable
var groups = []; // create empty array to hold groups - sortable
for (var i = 0, l = gnodes.length; i<l; i++){ // place elements in array so we can sort it
groups.push( gnodes[i] );
}
groups.sort(function(a,b){ // sort the array based on id
return (a.id > b.id) ? 1 : -1;
});
var counter = 1; // incremental number to define the tabindex
for (var i = 0, l = groups.length; i<l; i++){
var group = groups[i],
elements = group.getElementsByClassName('input'); // find all input elements of this group (must add class to all of them)
for (var e = 0, len = elements.length; e < len; e++){
elements[e].setAttribute('tabindex',counter++); // set tabindex
}
}
Demo at http://jsfiddle/gaby/sNekS/3/
Assuming that you're using Prototype (which you probably aren't), it would look like this :
Event.observe(window, 'dom:load', function() {
var inputs = [$$('#div1 input, #div1 a'), $$('#div2 input')];
var i = 0;
inputs.each(function(inputList) {
inputList.each(function(input) {
i++;
input.tabIndex = i;
});
});
});
Note: untested
<script type="text/javascript">
function TabNumbers() {
var t = document.getElementById('Div01').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 1;
}
}
var t = document.getElementById('Div02').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 2;
}
}
var t = document.getElementById('Div03').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 3;
}
}
var t = document.getElementById('Div04').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 4;
}
}
var t = document.getElementById('Div05').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 5;
}
}
var t = document.getElementById('Div06').childNodes;
for (i = 0; i < t.length; i++) {
if (t[i].tagName == 'INPUT' || t[i].tagName == 'SELECT' || t[i].tagName == 'BUTTON') {
t[i].tabIndex = 6;
}
}
}
</script>