»  Home  »  Programming  »  Building An Expanding DHTML Menu With CSS and JavaScript
Building An Expanding DHTML Menu With CSS and JavaScript
By Joseph De Araujo | Published 12/7/2005 | Programming | Rating: ratingfullratingfullratingfullratingfullratingempty Unrated |
Building An Expanding DHTML Menu With CSS and JavaScript

Introduction
Today I am going to show you the different parts that make up a dropdown vertical menu for your website. This is not like your normal dropdown menu, which appears at the top of your content, however -- these menus expand and remain visible until they are collapsed with the click of a mouse. The menu content actually expands with your page content, pushing the rest of whatever is below it down - so it can actually be used for more than just a menu (I might explore that a little later in another tutorial).

For now, let's get it started...


What does the finished menu look like and how does it function?


Here's a snapshot of what the menu looks like all coded up.

When you click on one of the links ie. Menu 1, Menu 2, Menu 3, Menu 4, Menu 5, this will expand or contract the submenu for that menu item. Basically, the end user must have JavaScript enabled to allow the submenus to work.


Let's build the menu html

First I'm going to start with the 5 menus items. Here's the code that I'm using, which is very simple; 5 hyperlinks. I will need to apply a style to these level one links, so I will make a class style called "menu1".

<a class="menu1">Menu 1</a>
<a class="menu1">Menu 2 </a>
<a class="menu1">Menu 3 </a>
<a class="menu1">Menu 4 </a>
<a class="menu1">Menu 5 </a>

Now I will create the menu1 class style and put it in the head of my document. So far we haven't done anying revolutionary. I won't explain the style that I've applied here because it's pretty straight forward - it's just a background image and the display:block makes it display like a rectangle.

<style type="text/css">
.menu1{
background-image:url(images/menudiv1bg.gif);
margin-left:25px;
padding-left:20px;
padding-top:2px;
padding-bottom: 2px;
display:block;
text-decoration: none;
color: #000000;
height: 20px;
}
</style>

Now I'll add the sub menus in place exactly where they will appear. In this part, we will use some small tricks to setup the alignment. Firstly, we'll wrap the whole submenu in a div that has a unique id for each menu. You can choose your own names for the div tags, but the main purpose of the div having a unique id is so that JavaScript can target that div specifically and make it appear or disappear. I also add a class style called 'hide' so that I can choose to hide all of the submenus from within my style sheet. The links are then listed within the div just like the main menu items and are given a submenu class style, to allow me to control the look of those in my style sheet as well:

<a class="menu1" >Menu 1</a>
    <div id="mymenu1" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1">Menu 2 </a>
    <div id="mymenu2" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1">Menu 3 </a>
    <div id="mymenu3" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1">Menu 4 </a>
    <div id="mymenu4" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1">Menu 5 </a>
    <div id="mymenu5" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>

I'll add the submenu and the 'hide' style to my style sheet now:

.submenu{
background-image: url(images/submenu.gif);
display: block;
height: 19px;
margin-left: 38px;
padding-top: 2px;
padding-left: 7px;
color: #333333;
}

.hide{
display: none;
}


I'll also create the style that will show the hidden div tags (submenus):

.show{
display: block;
}


Creating the JavaScript
If you're not too familiar with JavaScript or are in a rush, feel free to just copy and paste the code shown below into your page header as is. There are no further tricky parts to setup as the JavaScript simply compares the current state of the chosen submenu and then swaps it, meaning that if it's hidden, then it will be made visible, and vice versa.

Here's the code:

 
<script language="JavaScript" type="text/JavaScript">
<!--
menu_status = new Array();

function showHide(theid){
    if (document.getElementById) {
    var switch_id = document.getElementById(theid);

        if(menu_status[theid] != 'show') {
           switch_id.className = 'show';
           menu_status[theid] = 'show';
        }else{
           switch_id.className = 'hide';
           menu_status[theid] = 'hide';
        }
    }
}

//-->
</script>

Place this code in the <head> part of your web page. Next, I'm inserting the onClick event to the main menu links to call the showHide function when you click on the link:

<a class="menu1" onclick="showHide('mymenu1')">Menu 1</a>
    <div id="mymenu1" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1" onclick="showHide('mymenu2')">Menu 2 </a>
    <div id="mymenu2" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1" onclick="showHide('mymenu3')">Menu 3 </a>
    <div id="mymenu3" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1" onclick="showHide('mymenu4')">Menu 4 </a>
    <div id="mymenu4" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>
<a class="menu1" onclick="showHide('mymenu5')">Menu 5 </a>
    <div id="mymenu5" class="hide">
        <a href="#" class="submenu">Link One here</a>
        <a href="#" class="submenu">Link Two here</a>
        <a href="#" class="submenu">Link Three here</a>
        <a href="#" class="submenu">Link Four here</a>
    </div>


Some Geek Speak, for those who just want to know what's happening in the code.
Ok. What's happening here is that when the page loads, the JavaScript and CSS styles in the head will load first and then your menu links will appear in the body of the page. JavaScript is loaded from top to bottom by the browser, so let's read from inside the script tags:

The menu_status = new Array(); line will create a container ready to store the current state of your menu. This corresponds to the sections of the code that actually say what this menu_status now equals. eg. menu_status = 'show'; and menu_status = 'hide';

There's a function called showHide(theid) but this won't do anything unless it is called from within your HTML code. 'theid' is the id of the menu being shown or hidden, and it's called during the onClick even of that menu, such as onclick="showHide('mymenu5')".

Ok, so the function loads ready to be used, but the page continues to load...

Your main links and submenus load, but only the main links show because the 'hide' style that's applied to the submenus will hide the submenus. The submenus have in fact loaded already, they just aren't showing just yet.

If you click on a main menu link, then here's what happens:
 

  • The onClick event will fire up the showHide function and JavaScript will know which object we are working with by the id of the link.
  • JavaScript will get the menu element in question by the id that's passed to the function
  • JavaScript now has to check whether the current menu_status is visible or not, and then swap it. If it's not 'show' eg. if(menu_status[theid] != 'show') then the status_id will be made to equal 'show'. If it's not hide, eg. if(menu_status[theid] != 'hide') then it will be made to equal 'hide'.

Conclusion
In this article I've shown you how to build a basic vertical drop down menu using DHTML and JavaScript. This is a groovy little script that will allow you to create a nice menu, or even save you some space if you currently have multi level menus laid out on your site. You can probably do more with this script if you're familiar with JavaScript or don't mind experimenting, but we'll leave it at that for now!

86 Responses to "Building An Expanding DHTML Menu With CSS and JavaScript"


 
Jennifer Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 26 Dec 2005 3:02:22 PM CDT
This is excellent! Thank you very much! Your tutorial of an expanding menu was just about the only one that I understood, and wasn't needlessly complicated. It is also very cross-platform, which isn't something I can say for some of the others I've run across. I will definetely reccomend your tutorial(s) to others when asked. Linked in my favorites and from my website.

Thank you again,
Jennifer

 
an unknown user Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 08 Jan 2006 6:54:36 PM CDT
Thanks for the help, it actually worked!

[ Editors note: Really? It worked? Funny that :) ]

 
Tari Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 01 Feb 2006 7:58:47 PM CDT
Yay! Thank you so much! It's exactly what I was looking for. I'd found a way over complicated version that didn't work with 3 layers cause you could only have one menu open and I couldn't work out how to stop that. But this is perfect! Such simple coding too, I think I may learn it _

 
Ronald Weller Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 04 Feb 2006 5:25:39 PM CDT
Yeah just what I needed. And similar to comment #2 I´ve been searching the net over and over for a simple and flexible "3-layer-expanding-menu" et voilá I found it here. And last but not least I understood what I did. Thanks to you.

 
Neil Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 08 Feb 2006 12:46:32 PM CDT
Nice. but the cursor des not change on mouse over like it would fr a normal button. It will through some people i am sure

 
Fabian H Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 23 Feb 2006 8:46:02 PM CDT
Excellent article. simple & powerful.
Although I would like to get the background images used inside the CSS code in order to get the exact appeal of the example image. It looks wonderful!

 
Aaron Rating: ratingfullratingfullratingfullratingfullratingempty Unrated
said this on 12 Mar 2006 5:43:58 PM CDT
Very simplified article... good to see someone get it right. I would like to learn how to add persistent states to this function. I'm sure it would be as simple as adding a cookie function into the .js, I guess that's the next tutorial I'm looking for.

 
Iona Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 21 Mar 2006 5:59:49 AM CDT
Excellent, thank you so much, this is simple, elegant and it works. Some info on creating persistant states would be very useful. Thanks again.

 
isobar Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 02 Apr 2006 4:55:16 AM CDT
Very nice! I modified the script slightly to hide sub-menus for non-clicked items;

The Javascript:
function showHide(theidPrefix, theidNum)

// show/hide clicked menu element
if (document.getElementById)
var switch_id = document.getElementById(theidPrefixtheidNum);

if(menu_statustheidPrefixtheidNum != 'show')
switch_id.className = 'show';
menu_statustheidPrefixtheidNum = 'show';
else
switch_id.className = 'hide';
menu_statustheidPrefixtheidNum = 'hide';


// hide non-clicked menu elements
n = 1;
while( document.getElementById(theidPrefixn) )
if(n !== theidNum)
var hide_id = document.getElementById(theidPrefixn);
hide_id.className = 'hide';
menu_statustheidPrefixn = 'hide';

n;




To use it, the onclick function call on your links is modified to be:
onclick="showHide('mymenu', 2)"

The <div> IDs stay the same, ie "mymenu1", "mymenu2", etc.

 
Lekan Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 22 Jan 2008 10:16:24 AM CDT
thks for a great update to the script. I don't know javascript and was trying to use the updated script:



Do you know why it is not working?

 
Jerry Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 30 Apr 2006 10:43:15 PM CDT
I liked how the geek speak was at the bottom. I am just an 18-yr-old interested in computers and I learned html and am beginning javascript. Your methods were new to my experience and interesting to peruse.

 
mete kamil Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 20 May 2006 8:27:09 PM CDT
very nice! i will be sure to use! :-)

 
Vishal Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 08 Jun 2006 10:52:01 PM CDT
yeap, this is good stuff, but a little of putting the menus in persistent state would make this script even better, hope someone is working on the persistent method.

 
chili Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 21 Jun 2006 10:39:23 AM CDT
this is great! It took me long time to find such a useful and simple solution to create a nice menu!

 
Josh Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 21 Jun 2006 5:05:48 PM CDT
Great tutorial, very easy to understand. I am also looking for a persistent state of this. Also for teh person that suggested putting in href="javascript:?" in the link to create the normal mouseover action works but creates an error on the page. Anyone know a way to remove this error?

 
UltimaniumX Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 28 Jun 2006 3:43:21 PM CDT
To fix the error with making the menus have a "click cursor", instead of typing href="javascript:?", type href="javascript:;". That way, the actual javascript will run normally, even though there is nothing to run in the script.

 
Joel Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 05 Jul 2006 4:24:34 PM CDT
Thanks a lot! This is exactly what I've been looking for

 
Brad Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 11 Jul 2006 2:01:14 AM CDT
This was very helpful - thanks!!!

 
Lucia Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 11 Jul 2006 9:51:46 AM CDT
Thank You so much ... I've been looking for this for ages, never found a script for this half as good or half as clean... Thanks again!

 
Faz Raja Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 20 Jul 2006 11:55:17 PM CDT
Excellent! I was browsing the net for a while and all the tutorials were so difficult to understand.This was so easy to understand.Nice Job!!

 
satyanarayana Murthy Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 16 Aug 2006 5:18:59 AM CDT
Good ones indeed....
Regards
Satya

 
Doug Lawrence Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 28 Aug 2006 2:13:31 PM CDT
I've looked at many and this is the best and cleanest one.

 
Jennifer Perez Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 30 Aug 2006 10:37:10 PM CDT
Excellent article...to the point and complete...Loved it.

 
jocelyn Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 09 Sep 2006 3:46:53 PM CDT
thank you so much for this code! I'm 13, and even I understand it! just what I was looking for :

 
Krishnasamy Sadasivam Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 12 Sep 2006 9:41:29 AM CDT
This is excellent!! Thank you so much !!

 
russ Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 18 Sep 2006 4:59:28 PM CDT
finally something thats easy to understand, excellent tut thanks for sharing your knowledge

 
Alex Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 21 Sep 2006 7:26:06 PM CDT
This was an amzazing tutorial thank you so much. One question though, how do you make the menu open when you just roll your mouse over? Please edit my comment and give me the code. Thanks.

 
Roopa Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 28 Sep 2006 5:05:16 AM CDT
Great job. THank you very much!!

 
Dave Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 04 Oct 2006 12:39:31 AM CDT
A good example and explained well. I suggest that you only need to query the current classname of the object and switch it between hide/show. Also you can collapse the last one expanded by keeping the name of the last expanded one.

<script>

var last_expanded = '';

function showHide(id)
{
var obj = document.getElementById(id);

var status = obj.className;

if (status == 'hide') {

if (last_expanded != '') {
var last_obj = document.getElementById(last_expanded);
last_obj.className = 'hide';
}

obj.className = 'show';

last_expanded = id;
} else {
obj.className = 'hide';
}
}


</script>

 
chitra Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 10 Oct 2006 1:45:29 AM CDT
thanks, that's exactly what i was looking for. if it worked for me i'll be able to make good presentation, thanks once again

 
Juha Nyman Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 12 Oct 2006 10:05:44 AM CDT
Thank you! This is everything I have needed!

 
martin Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 17 Oct 2006 4:52:48 AM CDT
how much of a geek does jerry at comment #7 sound. Jerry if your reading there's something you can gert to help your coding its called a life get out more and chase girls. Incidentally tutorial looks great just what I've been falling asleep looking for, for the last 20 mins

 
Arun Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 19 Oct 2006 3:30:06 PM CDT
Thanks!! This is exactly what I was looking for!!!

 
dane Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 21 Oct 2006 6:34:41 AM CDT
It is simple to understand and encouraging to learn new things. One thing I couln't get the background image covers the whole page . how do youmake it so that it didn't pass the menu boundry.thanx

 
J BIzzle Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 22 Oct 2006 11:41:52 AM CDT
If everyone had tutorials like this!

 
Nick Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 06 Nov 2006 10:01:16 AM CDT
Thanks this is great - and the extra JS script from Dave helped out a lot.

 
Fskhan Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 11 Nov 2006 10:17:34 PM CDT
Great tutorial GREAT ;)

 
Arjun Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 14 Nov 2006 7:21:08 AM CDT
Thanks

 
ronnie Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 16 Nov 2006 12:47:08 AM CDT
very nice and thanks to dave aswell

 
Victoria Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 19 Nov 2006 8:29:05 PM CDT
Excellent ! Just what I wanted - and easy to use.

 
Jet Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 30 Nov 2006 2:40:28 AM CDT
My goodness, if what all the comments
say are true, the author must be a heck
of a writer. He could be a new Dan Brown
if he switches to fiction writing. So,
to give due credit, congrats to the author.

 
Reza Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 05 Dec 2006 6:52:23 AM CDT
Thank You Dave.
Very Useful.

 
Chris Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 11 Dec 2006 8:27:17 PM CDT
Nice one. That puts a solid foothold in my slippery css learning curve.

 
CoolDudeBudMan Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 07 Jan 2007 7:29:20 PM CDT
Re: comment #26
Use href="#" instead of href="javascript:?"

 
Jesse Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 10 Jan 2007 2:53:46 PM CDT
Yes, very good work. I'd agree with others that state that it's a simple, straightforward and cross-platform menu, plus - it's described in a way that's easy to dissect and understand.

 
Sam Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 10 Jan 2007 3:04:57 PM CDT
Well written, clean and elegang - thanks!

 
Richard Rating: ratingfullratingfullratingfullratingfullratingfull Unrated
said this on 12 Jan 2007 9:16:37 AM CDT
How do I keep the menu open on the current page within a section?

Hope someone can help...

Cheers,
Great tut!

 
J Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 18 Jan 2007 11:07:23 AM CDT
Great Work. It really helped me out!

 
Vimala Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated
said this on 23 Jan 2007 2:56:31 AM CDT
Excellent. It is exactly the answer for my problem and it is very simple to understand. Thank you.

 
Saqib Rating: ratingfullratingfullratingfullratingemptyratingempty Unrated