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

new ilikemusic.com website goes live

posted on Friday 30th July, 2010 by neil

We've been busy with the guys from I Like Music over the past few weeks designing and building their new interface. The site is now live and we're all really excited about it. There are some new fe...

more>>

Bluebit rolling out Plesk for all web sites

posted on Wednesday 21st July, 2010 by neil

We are excited to announce that all our hosting customers will be able to use the well respected Plesk control panel provided by Parallels. We're currently rolling out 8.3 on all web sites but looking...

more>>

conGuu 1.13.0 update

posted on Thursday 8th July, 2010 by neil

We've been busy on the rollup to our big V2 launch and there are some more additional features now available in conGuu: Gallery manager - A new module for users who want to set up image galleries...

more>>

Southampton Cycle Challenge

posted on Wednesday 23rd June, 2010 by neil

We're signed up and ready to go on Southampton City Councils new "drive" to get people on their bikes across Southampton and Hampshire. Whilst two of us already cycle to work and a third walks ever...

more>>

conGuu 1.12.1 update

posted on Thursday 10th June, 2010 by neil

We've carried out a few tweaks and modifications in this latest point release. Here's what's new: VAT Support for ConGuu cart. This gives us the ability to set and change VAT rates and display a ...

more>>
loading icon Loading... Please wait.