In one of my previous blog entries, I gave a brief explanation on how to create an accordion navigation menu. Someone commented on that article asking me how to open up multiple panels and remember the state (expanded or collapsed) of each panel. Since these two requirements are not related to the concept of an accordion navigation, I decided to write this separate article on how to create a vertical collapsible navigation menu. The end result can be seen here.

Step 1: create a custom list template

Navigate to the template section of your current theme and create a list template from scratch. Assign it a name and a custom theme class. Then, edit the list template and copy and paste the following code snippets in the appropriate sections.

  • Before List Entry > List Template Before Rows (for example <table> <tr>)
<div id="vertical-collapsible-nav">
  • Template Definition > List Template Current
<div class="is-lvl1-current"><span id="#A01#">#TEXT#</span>
</div>
  • Template Definition > List Template Current with Sub List Items
<div class="is-lvl1-current"><span id="#A01#">#TEXT#</span>
<ul>
  • Template Definition > List Template Noncurrent
<div><span id="#A01#">#TEXT#</span>
</div>
  • Template Definition > List Template Noncurrent with Sub List Items
<div><span id="#A01#">#TEXT#</span>
<ul>
  • Sublist Entry > Sub List Template Current
<li>
  <a href="#LINK#" alt="#TEXT#" class="is-lvl2-current">
    <img src="#IMAGE#" #IMAGE_ATTR# />
    #TEXT#
  </a>
</li>
  • Sublist Entry > Sub List Template Noncurrent
<li>
  <a href="#LINK#" alt="#TEXT#">
    <img src="#IMAGE#" #IMAGE_ATTR# />
    #TEXT#
  </a>
</li>
  • After Sublist Entry > Sublist Template After Rows
</ul></div>
  • After List Entry > List Template After Rows (for example </tr> </table>)
</div>

Step 2: create and populate your navigation list

We now need to create a static list based on the list template we created in step 1. Include all navigation entries for your application in a parent-child hierarchy. The image below shows you the list entries that I used for the demo:

static list entries
static list entries

In the template definition in step 1, I make use of the #A01# substitution string to assign each first level list entry an id value. You can manage these values by navigating to the User Defined Attributes section at the bottom of the list entry detail page.

user defined attributes
user defined attributes

Please note that the list template we created in step 1 only supports a two-level hierarchy. List entries with a level number higher than two are simply being rendered as two-level entries. Also, pay attention to the Current List Entry section for each list entry. You might experience abnormal behaviour when you don’t take into account this setting.

Step 3: add the list to your pages

Page zero is ideal in this situation since you probably want to display the navigation menu on multiple pages. So just create a list region that uses the list we created in step 2.

Step 4: apply CSS to the list region

Here is how I styled mine in the demo:

/* first level menu */
div#vertical-collapsible-nav {
  width: 200px;
  background-color: #DDDDDD;
  border: 1px solid #9C9C9C;
}
div#vertical-collapsible-nav div span {
  display: block;
  padding: 4px 5px 4px 10px;
  font-weight: bold;
  color: #222222;
}
div#vertical-collapsible-nav div span:hover {
  background-color: #CCCCCC;
  cursor: pointer;
}

/* second level menu */
div#vertical-collapsible-nav div ul {
  list-style-type: none;
  margin: 0;
}
div#vertical-collapsible-nav div ul li {
  background-color: #F2F2F2;
  padding: 4px 5px 4px 18px;
}
div#vertical-collapsible-nav div ul li a {
  text-decoration: none;
  color: #222222;
}
div#vertical-collapsible-nav div ul li a.is-lvl2-current {
  font-weight: bold;
}
div#vertical-collapsible-nav div ul li a:hover {
  color: #3E9FFF;
}
div#vertical-collapsible-nav div ul li a img {
  vertical-align: middle;
  padding-right: 5px;
}

Step 5: include jQuery cookie

This jQuery plugin simplifies cookie management. Download the JavaScript file here. Upload this file as a static file in shared components and include it in on your page(s) or page template.

Step 6: the jQuery code

  • Function and Global Variable Declaration:
// return a unique array
Array.prototype.getUnique = function(sort) {
  var u = {}, a = [], i, l = this.length;
  for (i = 0; i < l; ++i) {
    if (this[i] in u) { continue; }
    a.push(this[i]);
    u[this[i]] = 1;
  }
  return (sort) ? a.sort() : a;
}
  • Execute when Page Loads:
var cookie = $.cookie("panelState"), collapsed = cookie ? cookie.split("|").getUnique() : [], cookieExpires = 7;

$.each(collapsed, function() {
  $('#' + this).siblings("ul").hide();
});

$("div#vertical-collapsible-nav div span").click(function() {
  var spanClicked = this;

  $(this).siblings("ul").slideToggle(300, function() {
    updateCookie(spanClicked);
  });
});

function updateCookie(el) {
  var tmp = collapsed.getUnique();

  if ($('#' + el.id).siblings("ul").is(':hidden')) {
    tmp.push(el.id);
  } else {
    tmp.splice(tmp.indexOf(el.id), 1);
  }
  collapsed = tmp.getUnique();
  $.cookie("panelState", collapsed.join('|'), { expires: cookieExpires } );
}

Source: http://stackoverflow.com/questions/3890524/jquery-menu-remembering-the-state-of-the-menu

There you go. Have a look at the demo.

Any problems or questions? Just post a comment.