Feb

10th

jQuery expandable navigation using nested UL's

posted on Tuesday 10th February, 2009 by mark

Before I begin, I am not claiming this to be a definitive technique, in fact as a relative new comer to jQuery it can no doubt be vastly improved, however I thought I would share my technique and invite people to tear it apart if they so wish!

My aim

Create a navigation menu using UL's and LI's with nested UL's that expand when their parent LI is clicked

I will be using the minified jQuery 1.3.1 library to achieve this. Get jQuery! Include this file in your HTML document's head before following this tutorial.

HTML Markup

<ul>
	<li><a href="#">Item 1</a></li>
	<li><a href="#">Item 2</a>
		<ul>
		<li><a href="#">Sub Item 1</a></li>
		<li><a href="#">Sub Item 2</a></li>
		<li><a href="#">Sub Item 3</a></li>
		</ul>
	</li>
	<li><a href="#">Item 3</a></li>
	<li><a href="#">Item 4</a></li>
</ul>

The above HTML markup will display an unordered list with 4 list items, the second of these list items having an unordered list nested within, this UL has 3 list items of its own. Each of these list items has its own anchor tag as they are to be used as navigation.

The CSS

As I will be using a class to toggle the visibility of the nested UL's on and off, we need to write a small piece of CSS so that the class will actually do something when it is applied.

.hidden { display: none; }

Thats it!

The jQuery

To make it easier to see which piece of code does what, each line of jQuery is commented to explain what it is doing.

// code to be run when the document has loaded
$(function() { 
		   
	 // add a class of hidden to any ul's that are the child of an li. As we set any elements with a class of hidden to have the property display: none, this will now hide these nested ul's when the page loads
	$('ul > li > ul').addClass("hidden");

	 // select any a tags that are children of a ul that contains an li that has both ul and li children. Apply a function to the selected elements that will fire when it is clicked
	$('ul li:has(ul li)').children('a').click(function() {
												  
// toggle the class "hidden" on the child ul of the li containing the a tag that has been clicked										 
		$(this).parent().children('ul').toggleClass("hidden");
		
		// return false so that the link is not followed	
		return false;

	});

});

Ignoring the comments and the document ready, this is a small script made up of 4 lines to allow you to implement expandable navigation using nested UL's.

... not quite finished!

The sharp eyed people reading this will realise that this script is not quite finished. What will currently happen is that the nested UL will be displayed to the user, and will only be hidden after the entire page has been loaded and the Javascript is run (I'm basing this on you placing your JS files at the bottom of the body as recommended by Yahoo). This will cause a flicker due to the content not being hidden until the entire page has loaded.

The solution to this Flash of Unstyled Content (FOUC) has kindly been documented by Karl Swedberg over at Learning jQuery, so many thanks to him for that solution.

I am going to avoid the FOUC by adding a few pieces of code to my HTML/CSS/JS, I will explain what effect each step has at the end. To begin, I added the following JS to my HTML page in the head.

<script type="text/javascript">
	document.getElementsByTagName('html')[0].className = 'js';
</script>

I also added the following code to my CSS:

.js ul li ul { display: none; }

Finally I added the following line to my jQuery, before the closing brackets of my function:

$('html').removeClass("js");

Ok, now I'll explain what this has achieved. The Javascript that I added into my head will run as soon as the page begins to load, and its purpose is to add a class of js to my HTML element. I then added a line to my CSS which will set any ULs within an LI inside an element with a class of js to display none as soon as the page begins to load, as a result we do not see the FOUC. Finally I added a line of code to my jQuery function which removes the class of js from my html element. As the nested ul's have already had a class of hidden applied to them by my function, it is no longer required, and also the toggleClass would not display the nested UL's even if it is fired due to nested UL's being set to display none.

Thanks for reading!

Download Source Files (.zip)
follow me on twitter badge

latest news

rss iconWhat we're saying on the blog

Opencart stock control module

posted on Tuesday 1st May, 2012 by Neil Brooks

We've been hard at work on a stock control module for Opencart as there is a distinct lack of a decent way of tracking stock in what we feel is a great ECommerce solution. This module allows you...

more>>

Register .uk domains for up to 10 years

posted on Friday 27th April, 2012 by Neil Brooks

From 1st May 2012, Bluebit will be able to register abnd renew .uk domains for up to 10 years. Not all providers will be doing this but we will be offering this functionality as soon as it is avail...

more>>

New European cookie law

posted on Monday 16th April, 2012 by Neil Brooks

As you may be aware, the government passed a law just under 1 year ago regarding the use of cookies on websites. The responsibility for ensuring that you inform users of cookie use falls squarely o...

more>>

Glossary of terms

posted on Friday 16th March, 2012 by neilb

We wanted to put this glossary of common terms so that you could impress you partner/neighbour with your knowledge and ultimate geekiness, as well as being a useful resource when talking to one of ...

more>>

Using jQuery Cycle in a Responsive Layout

posted on Thursday 16th February, 2012 by markj

This post was inspired by this thread on the jQuery forum and the solution was found within those posts. I wanted to lay the solution out in a more digestable manner, hence this post. Please note, ...

more>>
view our recent web design work
loading icon Loading... Please wait.