Focusable Elements with tabindex

By  on  

I was recently debugging a Dojo-fueled web application that features a "Tree" dijit (much like Christoph Pojer's MooTools Tree Component). The tree's container had a fixed width and an CSS "overflow" property of "hidden" to avoid scrolling. The problem I was encountering was that when I clicked a tree item, the item would receive focus and, if it were too long, the left side of the container would get "cut off." Of course I could add overflow:auto to the container but the goal was to avoid scrolling with the element.

I spent hours trying to figure out how to avoid this "left-side cutoff." I tried using different CSS positioning, display types, and floating. I tried using Dojo to listen to tree item focus events and quick scroll back to the left -- that didn't work either. After hours of researching and testing, I found a method within the Dijit TreeNode class called setFocusable:

setFocusable: function(/*Boolean*/ selected){
	// summary:
	//		A Tree has a (single) node that's focusable.
	//		Mark that this node is/isn't that currently focsuable node.
	// description:
	//		In particular, setting a node as selected involves setting tabIndex
	//		so that when user tabs to the tree, focus will go to that node (only).

	this.labelNode.setAttribute("tabIndex", selected ? "0" : "-1");
},

The method modifies the tabindex attribute of the element. Initially I didn't think it could be possible that this was the problem. After a few quick tests, however, it was apparent that tabindex was causing the problem. I did a quick search and hit Jonathan Snook's Making Elements Focusable with tabindex post. Snook explains:

The tabindex value can allow for some interesting behaviour.

  • If given a value of "-1", the element can't be tabbed to but focus can be given to the element programmatically (using element.focus()).
  • If given a value of 0, the element can be focused via the keyboard and falls into the tabbing flow of the document.
  • Values greater than 0 create a priority level with 1 being the most important.

After a bunch more testing (...and cursing) I realized just how powerful tabindex can be. For those of you who prefer to read code, here's an example usage:

<a href="https://davidwalsh.name">Some Link</a>
<!-- ...tabs to.... -->
<span id="my-span" tabindex="0">Some Span</span>

And I can use JavaScript to focus on it!

document.getElementById('my-span').focus();

The A element wouldn't usually tab to the SPAN element but thanks to tabindex, it does. Imagine how much more powerful tabindex can be when used with JavaScript, as evidenced by the original Dojo snippet. I can programitically give or remove the ability for any element to receive focus by modifying its tabindex attribute. Sweet!

Part of me feels like I should have known about tabindex with focus() sooner -- the other part of me feels like it's a quirk that's not very commonly used. What do you think?

Recent Features

  • By
    Create a CSS Flipping Animation

    CSS animations are a lot of fun; the beauty of them is that through many simple properties, you can create anything from an elegant fade in to a WTF-Pixar-would-be-proud effect. One CSS effect somewhere in between is the CSS flip effect, whereby there's...

  • By
    CSS vs. JS Animation: Which is Faster?

    How is it possible that JavaScript-based animation has secretly always been as fast — or faster — than CSS transitions? And, how is it possible that Adobe and Google consistently release media-rich mobile sites that rival the performance of native apps? This article serves as a point-by-point...

Incredible Demos

  • By
    Introducing MooTools ScrollSide

    This post is a proof of concept post -- the functionality is yet to be perfected. Picture this: you've found yourself on a website that uses horizontal scrolling instead of vertical scrolling. It's an artistic site so you accept that the site scrolls left to right.

  • By
    Form Element AJAX Spinner Attachment Using MooTools

    Many times you'll see a form dynamically change available values based on the value of a form field. For example, a "State" field will change based on which Country a user selects. What annoys me about these forms is that they'll often do an...

Discussion

  1. CTuLT

    \(^O^)/ You finally learned Dojo! Still much more to learn, but you learned the basics! I have been using Dojo for 4 years and I still don’t know it all.

  2. MLaZz

    I used tabindex on my MultiSelect plugin (http://mootools.net/forge/p/mutiselect) to allow for keyboard navigation. Other than that i0ve never used it before, never needed..

  3. Luke

    I never realised that setting tabindex to -1 or 0 performed that behaviour… What I read when I first started learning HTML…going back a while XD, is that 0 is the start… now that just tells me I learnt from an in-accurate source, what they also said is that tabindex should take a value from 0-x, which also left me in the dark about using -1 to ignore an element. What you said is exactly right that tabindex is alot more powerful than it first appears and I think it opens quite a few door ways to custom and/or complex kayboard navigation.

  4. Great tutorial !
    I test with jQuery , it’s work:
    `document.getElementById(‘focusi’).focus();`
    I suggest you add in the github

  5. Pat Nellesen

    Thanks for the info about tabindex – I wasn’t aware of that behavior either (and I’ve been doing this stuff for a very long time ;) )

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!