Friday, September 18, 2009

jQuery Animated Tree Menu

Tree Menu is another important form of navigation menu and is used widely where the content has to be organized in a tree or windows folder like structures. To design our Tree Menu we’ll be using simple unordered lists in HTML and the power of jQuery to animate it. With little CSS trick I have implemented 2 different styles of tree, one by placing the node icon at branch end and second by placing node icon at branch bifurcation.

Benefits of using this Tree Menu:

  1. Zero coding required.
  2. jQuery based Menu compliant with all the browsers.
  3. Easy to manipulate jQuery code.
  4. Functionality for Expanding, Contracting, and Toggling the nodes in one click.
  5. Choose between 2 different styles just by editing only two lines in CSS code.
  6. Minimal CSS used which you can modify based upon your preferences.

This is how the two styles look like:

jQuery Tree Menu jQuery Tree Menu
Style 1: Node icon at branch end. Style 2: Node icon at branch division.

 

Download other images used for tree branch and nodes (click on image to open in new window):

plus minus blank branch
plus.gif minus.gif blank.gif branch.png

Using the mighty power of jQuery, performing tedious operation on HTML DOM elements like selection and animation just becomes more and more easy. Using jQuery this task has been accomplished in less then 10 lines whereas in traditional JavaScript it would have taken up close to 100 lines. I have used nested unordered lists (ul) inside list items (li) to create child tree’s so I’ve implemented jQuery selection wrapper as li:has(ul) to select all li nodes with children ul. The JavaScript code is pretty easy to understand, initially when the page loads the tree is initialized as follows:

  1. All tree nodes with children ($('.tree li:has(ul)')) are assigned the plus node icon and all the child nodes are hidden initially.
  2. A click event is assigned to all nodes with children ($('.tree li:has(ul)')). Click event uses the toggle function to show/hide the children of any node and change node icons.
  3. All leaf nodes ($('.tree li:not(:has(ul))')) are assigned blank node icon.
  4. Every last child’s ($('.tree li:last-child')) background images is changed to give the branch ending effect.

Apart from the initialization function I’ve also provided functions for single click Expansion, Contraction and Toggling of Tree nodes. jQuery’s show and hide functions are used to show/hide the children. The toggling and show/hide speeds can be set to ‘slow’, ‘normal’, or ‘fast’.

Put the following JavaScript code in the head section of your page.
JavaScript Code:
<script type="text/javascript" src="http://jqueryui.com/latest/jquery-1.3.2.js"></script>
<script type="text/javascript">
//Developed By: Abhinay Rathore
//Blog: web3o.blogspot.com

$(function(){ //initialize Tree Menu when page loads...
      //For all nodes with children under tree: hide all child nodes initially and change list image
      $('.tree li:has(ul)').css({cursor:'pointer','list-style-image':'url(plus.gif)'}).children().hide();
      //Assign Click event to all nodes with children
      $('.tree li:has(ul)').click(function(event){
            if (this == event.target) { //if target element of the event matches 'this'
              //toggle list image and show/hide children using toggle('fast') method
              $(this).css('list-style-image', ($(this).children().is(':hidden')) ? 'url(minus.gif)' : 'url(plus.gif)');
              $(this).children().toggle('fast');
            }
            return true;
      });
      //For all nodes with no children: change list image to blank
      $('.tree li:not(:has(ul))').css({cursor: 'pointer','list-style-image':'url(blank.gif)'});
      //Change Background image for every last child
      $('.tree li:last-child').css({'background':'url(branch.png) 0px -1970px no-repeat'});
});
//Expand all tree nodes
function ExpandTree(){
      $('.tree li:has(ul)').css('list-style-image', 'url(minus.gif)');
      $('.tree li:has(ul)').children().show('fast');
}
//Contract all tree nodes
function ContractTree(){
      $('.tree li:has(ul)').css('list-style-image', 'url(plus.gif)');
      $('.tree li:has(ul)').children().hide('fast');
}
//Toggle all tree nodes
function ToggleTree(){
      $('.tree li:has(ul)').click();
}
</script>

I have created this Tree Menu with minimal CSS required. You can add extra styling to match the color and styling of your website. For switching between the two styles shown above, you can make the appropriate changes in the CSS as shown in comments below. If you want to change the font size or margins on the tree nodes, you might have to adjust the CSS along with the branch image provided in this post.

CSS Code:
<style type="text/css">
<!--
.tree {
      font-family: Verdana, Geneva, sans-serif;
      font-size: small;
      margin: 10px; padding: 0px;
}
.tree ul { margin: 0px; padding: 0px; } /* Disable this for 2nd Style */
.tree li {
      padding: 5px 0 1px 30px; /* Use this for 1st Style */
      /*padding: 5px 0 1px 10px; /* Use this for 2nd Style */
      margin: -3px 0px 0px -10px;
      background: url(branch.png) 0px 0px no-repeat;
      list-style-position: inside;
}
.tree a{
      text-decoration: none;
}
-->
</style>

The HTML code for the Tree Menu only consists of unordered list or items nested inside each other. Every list item (li) is considered a leaf node unless another unordered list (ul) is nested inside it. You can either use links or text inside list items. There is no restriction on the depth of the tree. I have also provided 3 links as examples on top to use for the one-click toggling functions.

HTML Code:
<a href="javascript:ExpandTree()">Expand All</a> |
<a href="javascript:ContractTree()">Contract All</a> |
<a href="javascript:ToggleTree()">Toggle All</a>

<ul class="tree">
    <li>Item 1
      <ul>
            <li><a href="#">Item 1.1</a></li>
      </ul>
    </li>
    <li>Item 2
      <ul>
            <li><a href="#">Item 1.1</a></li>
            <li><a href="#">Item 1.2</a></li>
      </ul>
    </li>
    <li>Item 3
        <ul>
            <li><a href="#">Item 3.1</a></li>
            <li>Item 3.2
                <ul>
                    <li><a href="#">Item 3.2.1</a></li>
                    <li><a href="#">Item 3.2.2</a></li>
                    <li>Item 3.2.3
                        <ul>
                            <li><a href="#">Item 3.2.3.1</a></li>
                            <li><a href="#">Item 3.2.3.2</a></li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li><a href="#">Item 3.3</a></li>
      </ul>
    </li>
    <li>Item 4
          <ul>
          <li><a href="#">Item 4.1</a></li>
          <li>Item 4.2
              <ul>
                  <li><a href="#">Item 4.2.1</a></li>
                  <li><a href="#">Item 4.2.2</a></li>
              </ul>
          </li>
          </ul>
    </li>
    <li>Item 5
      <ul>
            <li><a href="#">Item 5.1</a></li>
            <li><a href="#">Item 5.2</a></li>
      </ul>
    </li>
</ul>

Looking at the Tree Menu code above and comparing it with the functionality it provides, you must have realized the power of jQuery which make HTML DOM selection and event handling so seamless and easy to use.

del.icio.us Tags: ,,

5 comments:

  1. I tested this script but the links are not clickable (the ones with <a href...). Do you know why that is?

    ReplyDelete
  2. Hey Bernhard,
    There a bug in the JavaScript code because of which this is happening.
    Just change the return statement for the click event to return 'true' in the page load function.

    ReplyDelete
  3. Hi

    Looks great. How can can I expand and show a element on load e.g Item 3.2.1 just like the "Blog Archive" on this page

    ReplyDelete
  4. This is a great menu, very smooth.
    The only problem I've been having is that the branch.png doesn't seem to show up when declared in the CSS.
    If I add the line:
    $('.tree li').css({'background':'url(branch.png) 0px 0px no-repeat'});
    in the Javascript function it shows up fine.

    ReplyDelete
  5. Hey!

    A really super useful tree menu!

    But...

    Is it possible to leave a specific branch open, when i open the page from a specific link?

    ReplyDelete

Thanks a lot for your valuable comments :)