jQuery accessible ARIA tree control: from the book Designing with Progressive Enhancement

Posted by Scott on 02/17/2010

Tree controls are one of the most popular ways to represent hierarchical information in web interfaces — they present deeply nested, multi-level content in a compact space, and allow users to expand and collapse nodes to control which parts of the tree structure are displayed.

Today, we’re releasing a jQuery tree control plugin that uses progressive enhancement to transform an unordered list (UL) into a dynamic tree control, complete with accessibility features like ARIA attributes, keyboard and mouse behavior, and focus management. In the following article, we’ll give a brief overview of the purpose of this widget and how you can use it in your projects.

This widget is one of the 12 fully-accessible, project-ready, progressive enhancement-driven widgets we created to accompany our new book, Designing with Progressive Enhancement. Purchasers of the book can access all twelve examples immediately (and we’ll be releasing selected others publicly as open source over the next couple of months as well).

How does this widget work?

This widget provides all the essential features for a basic tree control, with a focus on providing great support for keyboard users and those with disabilities.You can expand and collapse the folder nodes either by clicking them or pressing the left and right arrow keys. The up and down arrows traverse the tree, and clicking the document nodes will navigate to their URL. (NOTE: In this demo, the document file links are set to ‘#’, so they won’t actually go anywhere.)

We’ve also implemented a roving tabindex to preserve the active node in the tree. When you first arrive on the widget the first item in the tree is active by default; if the user changes the focus and tabs away from the control, and then tabs back to it, focus goes to the last active item.

The following example demonstrates the tree plugin, displayed with folder and document icons to represent a file tree:

jQuery Accessible ARIA Tree widget

Note about EnhanceJS: This demo runs on our EnhanceJS framework, which applies progressive enhancement based on browser capabilities, ensuring an accessible page to the widest audience possible. EnhanceJS also adds a “view low-bandwidth version” link beneath the tree control (for users looking at the enhanced version of this site). If you click the link to view the low-bandwidth version of the demo, just remember that you’ll need to click it again to view the enhanced version of this site on future views. You can read more about EnhanceJS at the following article: Introducing EnhanceJS: A smarter, safer way to apply progressive enhancement

How do I use it?

To use this script in your page, you’ll need to download and reference both jQuery and jQuery.tree.js, as well as the associated CSS for the tree (download instructions are found below), and call the tree method on any list element on the page. For example, to create a tree control from a ul element with an id of files, find it using jQuery and call the tree method on it:


Note: be sure to use jQuery’s $(document).ready event to wait until the DOM is ready before running the tree script.

You can also call the tree method on several multi-level hierarchical lists at once to change them all into tree controls. For example, this will turn any ul in a #content container into trees:

$('#content ul').tree();

This plugin is very simple by design, and includes a single option for setting a node (or nodes) open by default. Simply pass in one or more list item selector(s) to the expanded option. For example, to open the first node in the tree by default:

  expanded: 'li:first'

Or to expand a list item with an id of documents:

  expanded: '#documents'

It’s possible to open several nodes by assigning a class to several list items and referencing that class with the expanded option:

  expanded: '.default-expand'

That’s all there is to it!

To understand in detail how this widget works under the covers, and to learn about how to apply the principles in different interactions or more complex scenarios, we recommend purchasing a copy of Designing with Progressive Enhancement.

Download (and help us improve) the code

The tree plugin code is open source and available in a git repository, jQuery-Tree-Control. If you think you can help on a particular issue, please submit a pull request and we’ll review it as soon as possible.

If you’ve already purchased Designing with Progressive Enhancement, you can download all twelve widgets at the code examples download page.


Interesting.. but, I’m curious, why haven’t you released this tree plugin as a jQuery UI widget?
Also, have you used unit testing for it?

Comment by Valentino Aluigi on 02/22  at  05:51 PM

@Valentino: Our book deals with all the considerations involved in building widgets like this from scratch (well, almost from scratch… they all use jQuery). Building the code examples on the jQuery UI framework would have been outside of the focus of the book, but creating a UI-driven, ThemeRoller-ready version of this widget is definitely something we plan to do. All of the book’s code examples will eventually work their way into jQuery UI wherever they are helpful, whether it’s improving the ARIA implementation of existing UI widgets, or beginning the development of new ones. Since much of the hard work for this widget is figured out now, we can start creating a UI-driven version of this component right away in the jQuery UI project SVN. As for unit testing, we haven’t implemented unit testing in these widgets yet, but that’s a great idea. In all likelihood, that will come when we translate into jQuery UI.

Comment by Scott (Filament) on 02/22  at  06:13 PM

Nice but some strange behaviour when i press the spacebar when focused on an item. I do like the use of left and right to expand/collapse, but a lot of people are also used to using the spacebar to perform the same function.

When i press the space bar on this control, it scrolls the page down about halfway, completely hiding the tree. If i press space again it is stepping down the page. (Using Chrome on xp).

Comment by Darren on 02/22  at  07:14 PM

Great job Filament Group. And thank you for sharing your work with us. I’m looking forward to us getting this and many other bits into jQuery UI. What a boon.

I agree with Darren on the spacebar. I would expect the behavior to be the same as the Enter key.

Comment by Richard D. Worth on 02/22  at  08:30 PM

Thanks Richard and Darren! We agree that using spacebar to match the enter key’s (and mouse click’s) behavior would be a nice enhancement. We’ll post a comment when we get time to make that commit.

Comment by Scott (Filament) on 02/23  at  08:45 AM

@Richard, Darren: Thanks again for the input. Just committed the change. The spacebar behavior now matches the enter key. The downloadable zip above is updated and the change noted here: http://bit.ly/aJEfxm

Comment by Scott (Filament) on 02/23  at  10:17 AM

It definitely could work well as a jquery UI plugin.  Any plans to add drag-drop functionality to it?

Comment by Tyson Cadenhead on 02/23  at  05:29 PM

You should look into the recently released jquery 1.4.2. It is ~3 times faster than the version you’re currently running.

BTW, very, very nice site

Comment by Dave Rose on 02/28  at  01:08 AM

@Tyson: Good idea. Once it’s implemented in jQuery UI, it’ll be easy to extend its behavior with drag-drop, sorting, and more.

@Dave, Thanks for the compliment on our site. We’ll update the jQuery version when we get a chance, but this widget should work fine on jQuery 1.4.2. Please let us know if you run into any issues.

Comment by Scott (Filament) on 03/01  at  01:55 PM

Looks great! Only one problem I found. When a closed node is selected, the left keyboard arrow should navigate to the parent node.

Comment by David Radcliffe on 03/17  at  01:57 PM

@David: Thanks for the feedback, and sorry for the long delay in responding. We agree and added your suggestion to the issue tracker. You can follow its progress or even submit a patch here: http://code.google.com/p/dwpe/issues/detail?id=32

Comment by Scott (Filament) on 08/12  at  10:43 AM

Quick update for anyone using this plugin:
Based on David’s suggestion above, we’ve improved our keyboard implementation to traverse to parent or child nodes when the left/right arrow keys are pressed and on a folder that is already collapsed or expanded.

The zip is updated.

Comment by Scott (Filament) on 08/12  at  11:08 AM

Well, my expanded option doesn’t work.

expanded: ‘#open’

and, here is chunk of the html code:

<ul id="files">
<li>My Documents
<li>Christine’s Files
<li>Gift Registry.doc</li>
<li>Nathan’s Stuff
<li>Birthday Parties.doc</li>
<li>Area Playgrounds.doc</li>
<li>Travel Ideas
<li>Potential Places.doc</li>
<li>Travel Funds.doc</li>
<li id="open">Wedding Plan
<li>My Movies
<li>The Big Lebowski.m4v</li>
<li>Planet Earth.m4v</li>

Comment by Smith on 10/06  at  06:55 AM

Okay, I it is solved.
So, I have to put id="open" at all <li> traversing to the depth-most <li> that is expanded.
Thanks :)

Comment by smith on 10/06  at  12:39 PM

i was search this post from Google and its very good information.

Comment by recados para orkut on 01/26  at  03:01 PM

Any ideas how to use this for navigation, which is probably the most common application for a tree - right now clicking just opens/closes the node. I currently don’t have have a consistent idea how to allow it to add the possibility to follow a link: maybe add an additional icon? Or respond to a double-click?

Comment by Stefan on 06/10  at  06:30 AM

jsTree lets developers define rules for moving, selecting, deleting, and focusing nodes. The rules are based on developer-definable types of each node passed in the data (different sources define it differently). This limits the user in his actions. The developer can also attach inline rules which override global rules. One scenario in which these rules are useful is when you build a CMS and need a fixed number of top level nodes because of a design restriction.

Comment by Cheap SSL on 06/21  at  01:40 AM