Resetting TabIndex When Adding and Removing DOM Elements

Recently I have had a nagging issue I honestly had a hard time recreating, till today that is. The situation occurred when I added and removed DOM elements in reaction to a user checking and unchecking a checkbox. If the user tabs to the next field, they would find themselves at the top of the form, not the next field in logical order.

If you recall you should define the tabindex attribute for any form element so the user can simply tab through the fields without grabbing the mouse. In this case the user would change the state of the checkbox by pressing the spacebar, not using their mouse. Which brings up a point, you should always test your forms without using your mouse, get it out of your site!

Now this issue took a while for me to recreate, I just could not figure it out. In fact I tried in several browsers, but finally my persistence paid off and it finally happened to me.

To demonstrate the issue I am going to use the form below. The form contains a checkbox for the user to indicate if they have an e-mail address. It is checked by default simply so it makes sense in this context. If the user unchecks the checkbox the e-mail line is removed from the form. If they check the checkbox the e-mail line is restored or added to the DOM.

<

form

>


<

ul

>


<

li

><

label

for

="firstName"

>

First Name

</

label

>


<

input

id

="firstName"

name

="firstName"

tabindex

="10"

></

input

></

li

>


<

li

><

label

for

="lastName"

>

Last Name

</

label

>


<

input

id

="lastName"

name

="lastName"

tabindex

="20"

></

input

></

li

>


<

li

id

="lihaveEmail"

><

label

for

="haveEmail"

>

Do You Have An E-Mail?

</

label

>


<

input

id

="haveEmail"

name

="haveEmail"

type

="checkbox"

tabindex

="30" checked

></

input

></

li

>


<

li

id

="liEmail"

><

label

for

="email"

>

E-Mail

</

label

>


<

input

id

="email"

name

="email"

tabindex

="40"

></

input

></

li

>


<

li

><

button

type

="submit"

id

="btnSubmit"

tabindex

="100"

>

Save

</

button

></

li

>


</

ul

>


</

form

>


This is the form as it is initially loaded by the browser. I have tabbed through the form to set focus on the checkbox. Pressing the space bar will uncheck the checkbox and remove the e-mail line.

with-email-line

Now here is where some magic happens because I have custom check event function defined that I am not going into the details in this post. The code is included in the download of this sample page. Basically it is architected like the $.click() function that wraps the click event interactions. So in this demo the check event function executes the toggleEmail() function as its click event handler. The toggleEmail() receives a reference to the checkbox, which the checked property indicates the checkbox’s current state.

$(

"#haveEmail"

).check(toggleEmail);

function

toggleEmail(value){

if

(!value.

checked

){

$(

"#liEmail"

).remove();

}

else

{

$(

"#lihaveEmail"

)
.after(

"<li id='liEmail'><label for='email'>E-Mail</label>"

+

"<input id='email' name='email' tabindex='40'></input></li>"

);

}

$(

"#haveEmail"

).focus();

}
If the checkbox is checked the e-mail line is removed, otherwise it is added. Just a little side note, to make it easy to restore the e-mail line in the same place I gave the checkbox line an id of lihaveEmail and use the $.after() function.

with-email-line[1]

As you can see, unchecking the checkbox removes the line. But if you are using IE 8, there is a chance the DOM reflow caused the tab focus to be reset to the top of the form, not retained on the checkbox. I say in IE 8, I could not recreate this issue in any other browser, and I did not have access to a previous version of IE.

The way I ‘fixed’ this issue was explicitly setting focus, $("#haveEmail").focus();,  on the checkbox after the element was added or removed from the DOM. Now you can continue to tab through the form naturally.

So while this was a very pesky issue I had to recreate, it is easily solved with a little explicit coding.

Share This Article With Your Friends!