Flat jQuery Accordion Menu Tutorial

In this post, I will be showing how to create a two level, jQuery accordion menu. What's special about this menu is that we will be using jQuery to count the number of items in the submenus and then show that number next to the parent item. For this tutorial, I am assuming you are fairly comfortable with the HTML and CSS. I will explain a little bit about them, but the focus of this tutorial will be in the jQuery code.

Note:

Download more of our free jQuery Menus and Accordion Menus.

Demo

This is what our final product will look like when we are done. If you want you can download the complete Source Code inside our Menu Maker.


The HTML

So the HTML for this menu is very simple. All we need is a Nested Unordered List and a containing DIV. Notice that we also wrapped our link text with a SPAN element. We will need this later to achieve the styles we want.

<div id='cssmenu'>  
  <ul>
    <li><a href='#'><span>Home</span></a></li>
    <li><a href='#'><span>Products</span></a>
      <ul>
        <li><a href='#'><span>Widgets</span></a></li>
        <li><a href='#'><span>Menus</span></a></li>
        <li><a href='#'><span>Products</span></a></li>
      </ul>
    </li>
    <li><a href='#'><span>Company</span></a>
      <ul>
        <li><a href='#'><span>About</span></a></li>
        <li><a href='#'><span>Location</span></a></li>
      </ul>
    </li>
    <li><a href='#'><span>Contact</span></a></li>
  </ul>
</div>  

The CSS

The CSS code for this menu is not to complicated when we break it up. To start off with we are importing a great Google Font called Open Sans. We are doing this with the @import command at the very top of the stylesheet. If you haven't used Google Fonts before they are a great, free way to use stylish fonts on your website. After this, we want to include our CSS resets so that we have a good base to build our styles from.

@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,600,300);
#cssmenu,
#cssmenu ul,
#cssmenu li,
#cssmenu a {
  margin: 0;
  padding: 0;
  border: 0;
  list-style: none;
  font-weight: normal;
  text-decoration: none;
  line-height: 1;
  font-family: 'Open Sans', sans-serif;
  font-size: 14px;
  position: relative;
}

#cssmenu a {
  line-height: 1.3;
}

Next up we want to style the first level of the menu. To create space for our numbering we give each of the A elements a right padding of 40px and then set their position to relative. Setting the position to relative will allow us to later position the numberings absolutely inside the 40px padding we created.

Also, take note of the .active and .cnt classes. These are not in our original HTML markup, but we will be applying these classes later via our jQuery.

#cssmenu {
  width: 250px;
}

#cssmenu>ul>li>a {
  padding-right: 40px;
  font-size: 25px;
  font-weight: bold;
  display: block;
  background: #bd0e36;
  color: #ffffff;
  border-bottom: 1px solid #5e071b;
  text-transform: uppercase;
  position: relative;
}

#cssmenu>ul>li>a>span {
  background: #ed1144;
  padding: 10px;
  display: block;
  font-size: 13px;
  font-weight: 300;
}

#cssmenu>ul>li>a:hover {
  text-decoration: none;
}

#cssmenu>ul>li.active {
  border-bottom: none;
}

#cssmenu>ul>li.active>a {
  color: #fff;
}

#cssmenu>ul>li.active>a span {
  background: #bd0e36;
}

#cssmenu span.cnt {
  position: absolute;
  top: 8px;
  right: 15px;
  padding: 0;
  margin: 0;
  background: none;
}

Finally, we have our submenu styles. Nothing to complicated right? All we are doing is hiding the submenus with the display: none; a style which will make all the sub-menus look collapsed when the page first loads. Again notice the .even and .odd classes. We will again me adding these classes via our jQuery.

#cssmenu ul ul {
  display: none;
}

#cssmenu ul ul li {
  border: 1px solid #e0e0e0;
  border-top: 0;
}

#cssmenu ul ul a {
  padding: 10px;
  display: block;
  color: #ed1144;
  font-size: 13px;
}

#cssmenu ul ul a:hover {
  color: #bd0e36;
}

#cssmenu ul ul li.odd {
  background: #f4f4f4;
}

#cssmenu ul ul li.even {
  background: #fff;
}

If we have done everything correctly up to this point we will have a menu that looks like the image below. If your menu doesn't look like this after creating the HTML and CSS then something went wrong. Circle back and double check out have all the correct CSS in place.

Flat jQuery Accordion Menu Tutorial

jQuery Setup

Alrighty, let's get started on that jQuery code. This is where everything starts coming together and we will be breaking it down step by step to simplify things. Before we get started we need to make sure that we are including the jQuery script in the header of our page. There are lots of ways to do this, but the easiest is to include the jQuery that is hosted by jQuery.

Place this little bit of code somewhere in the header of our page.

<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>  

Once we have the jQuery code installed on our page we can begin to code our custom jQuery. As with all jQuery code, we need to wrap everything in the document.ready function. When we place all of our jQuery code inside of this function, we are basically telling our code to wait until the page is loaded before we start running our code.

$(document).ready(function(){

// jQuery code goes here!

});

The jQuery

Now that we have wrapped our code the first thing we need to do is add our numbering to the first level elements. Essentially what we need to do is look at each first level element, check if it has a sub menu, and then count how many elements are in that sub menu.

The best way to go about this is to use the .each() function of jQuery to iterate through each sub menu. Any code placed inside the .each() function will run for each instance that matches our jQuery selector. Arguments to the .each() function are index and element, the element being the matched element from our jQuery selector.

Inside our .each() the function we first will create a variable that holds the number of sub-menu items. Below this is the count variable. The .length function will return the number of items in the sub menu. The second variable we setup is the content variable which simply wraps our count variable with an HTML span element. Recognize the .cnt class from our CSS code earlier? Finally, we find the parent LI element of our sub menu and append our newly created numbering element.

$("#cssmenu > ul > li ul").each(function(index, element) {
  var count = $(element).find("li").length;
  var content = "" + count + "";
  $(element).closest("li").children("a").append(content);
});

The next little bit of code will apply .even and .odd classes to the sub menu LI elements so that we can get the zebra stripe effects with our sub menus.

$("#cssmenu ul ul li:odd").addClass("odd");
$("#cssmenu ul ul li:even").addClass("even");

Finally, we need to create the functionality that lets our menu know what to do when an item is clicked. The bulk of our code is wrapped in the .click() function. Any code inside this .click() function will run each time a link from the first level of our menu is clicked. Below is that code:

$("#cssmenu > ul > li > a").click(function() {
  var checkElement = $(this).next();

  $("#cssmenu li").removeClass("active");
  $(this).closest("li").addClass("active");

  if (checkElement.is("ul") && checkElement.is(":visible")) {
    $(this).closest("li").removeClass("active");
    checkElement.slideUp("normal");
  }
  if (checkElement.is("ul") && !checkElement.is(":visible")) {
    $("#cssmenu ul ul:visible").slideUp("normal");
    checkElement.slideDown("normal");
  }

  if ($(this).closest("li").find("ul").children().length == 0) {
    return true;
  } else {
    return false;
  }
});

The main thing we want to do every time a link is clicked is to check whether is has a sub menu and then apply the appropriate functionality. We use the function .next() to grab the immediate sibling of the link when it is clicked. If the clicked link has a sub menu, then this value will be a Ul element. To make our code clean, we will assign the value of the .next() function to our checkElement variable for use later on.

The next two lines of code after we grab our .next() element will add an .active class to the element that was clicked.

The first if statements check to see if our checkElement is a UL and if it is visible. If so, it will remove the active class and then slide the sub-menu up.

The second IF statement will expand a sub-menu when its parent item is clicked. The IF statement checks to see if our checkElement is a UL element and if it is not visible. If these two conditions are true, then that means the menu item we clicked has a collapsed sub menu and that we need to expand it. We first collapse all the other sub menus that are visible with the .slideUp() function and then expand the current sub menu with the .slideDown() function.

Our final IF statement will determine whether to return TRUE or FALSE. Since we are clicking a link (A) element the browser naturally will want to follow the link inside the HREF to another page. When we return false we are telling the browser not to do this. The functionality we want is to expand a sub-menu if one is present, if not, then we will want to follow the link inside the HREF. Again we are using the .length function to see how many sub menu items the click link has. If it returns 0, we know that there is no sub menu present and we should just follow the link in the HREF

Conclusion

So there you have it! Easy, right? Hit up the comments section if you run into issues or have any questions. Also, make sure to check out our libraries of free CSS Menus and jQuery Menus.