Ramui webblog Free Blog Script

JavaScript drop down menu

A drop down menu is one in which menu items are normally kept hidden; only their parent nodes are visible to the viewers. When viewer clicks on a node, the node expanded vertically and the items under that node becomes visible. Here we shall discus how to develop a drop down menu for a web page with the help of JavaScript.

A CSS vertical menu

Below we take an example vertical menu which has three parent nodes- web hosting, web design and domain name. Under those parent nodes there are few children items. The HTML code of such a list is as follows.

Code | Download
<div id="fw_nav">
<ul id="nav">
<li><div class="caption">web hosting</div>
<ul>
<li><a href="#">windows hosting</a></li>
<li><a href="#">Linux hosting</a></li>
<li><a href="#">Reseller hosting</a></li>
</ul>
<li><div class="caption">web design</div>
<ul>
<li><a href="#">Free web tools</a></li>
<li><a href="#">Web design services</a></li>
</ul>
<li><div class="caption">Domain name</div>
<ul>
<li><a href="#">Free subdomain</a></li>
<li><a href="#">Free domin services</a></li>
<li><a href="#">Cheap domain registration</a></li>
</ul>
</div>

Now we shall add few lines of style to view this list more professional. Between <head> and </head> tags add the following lines of style.

Code | Download
<style type="text/css">
#fw_nav{margin:0;padding:0;}
#fw_nav a, #fw_nav a:hover, #fw_nav ul{font:11px arial;}
#fw_nav ul{width:210px;background:#f0f0f0;list-style-type: none; border-bottom: 3px solid #777777;margin:0; padding:0;}
#fw_nav li ul{position:relative;top:0;border:none;}
#fw_nav ul li a{margin:1px 0;border:1px solid #f0f0f0;padding:2px 4px; display:block;color:#333333;text-decoration:none;}
#fw_nav ul li a:hover{color:#442222;background-color:#dddddd;border-color:#666666;}
#fw_nav .caption{margin:0;border-top:1px solid #777777;color: #333333;font-weight:600; background-image:url('arrow.gif');background-color:#c6c3bb; background-position:3px center;background-repeat: no-repeat;padding:5px 4px 5px 18px;}
</style>

Correction for IE

As IE shows line breaks of HTML code of a list items so we have to add the following line at the top of the style definition to suppress that effect. Alternatively you can remove all new line character from your HTML code.
*html ul li a{height:1%;}

Up to this point it is a nice looking css vertical menu. You can view the resulting menu page here.

Vertical menu script

Now we have to add JavaScript code to make the menu dynamic. As I said the child items are kept hidden and become visible only when user clicks on the parent node. To realize this feature we have to switch the display property of the list item with the help of JavaScript. Add the following lines of JavaScript code at the top of the document (between <head> and </head> tags).

Code | Download
<script language="javascript">
<!--
function populate_menu(i){
if(i.parentNode.className=='show'){i.parentNode.className='hide';}
else{i.parentNode.className='show';}
}
-->
</script>

The above JavaScript function populate_menu() take one argument i as object and switch its parent css class between 'show' to 'hide' and vice-versa.

Now add the following two lines at the end of the style code to define the classes 'show' and 'hide'.

Code | Download
#fw_nav .show ul{display:block;}
#fw_nav .hide ul{display:none;}
#fw_nav .show div.caption{background-image:url('down_arrow.gif');}

Now add onclick event to all the caption node to call the JavaScript function populate_menu(). So the resulting code becomes as follows.

Code | Download
<html>
<head>
<title>drop down menu example</title>
<style type="text/css">
*html ul li a{height:1%;}
#fw_nav{margin:0;padding:0;}
#fw_nav a, #fw_nav a:hover, #fw_nav ul{font:11px arial;}
#fw_nav ul{width:210px;background:#f0f0f0;list-style-type: none; border-bottom: 3px solid #777777;margin:0; padding:0;}
#fw_nav li ul{position:relative;top:0;border:none;}
#fw_nav ul li a{margin:1px 0;border:1px solid #f0f0f0;padding:2px 4px; display:block;color:#333333;text-decoration:none;}
#fw_nav ul li a:hover{color:#442222;background-color:#dddddd;border-color:#666666;}
#fw_nav .caption{margin:0;border-top:1px solid #777777;color: #333333;font-weight:600; background-image:url('arrow.gif');background-color:#c6c3bb; background-position:3px center;background-repeat: no-repeat;padding:5px 4px 5px 18px;}
#fw_nav .show ul{display:block;}
#fw_nav .hide ul{display:none;}
#fw_nav .show div.caption{background-image:url('down_arrow.gif');}
</style>
<script type="text/javascript" language="javascript">
<!--
function populate_menu(i){
if(i.parentNode.className=='show'){i.parentNode.className='hide';}
else{i.parentNode.className='show';}
}
-->
</script>
</head>
<body>
<div id="fw_nav">
<ul id="nav">
<li class="hide"><div class="caption" onclick="javascript:populate_menu(this)">web hosting</div>
<ul><li><a href="#">windows hosting</a></li>
<li><a href="#">Linux hosting</a></li>
<li><a href="#">Reseller hosting</a></li>
</ul>
<li class="hide"><div class="caption" onclick="javascript:populate_menu(this)">web design</div>
<ul>
<li><a href="#">Free web tools</a></li>
<li><a href="#">Web design services</a></li>
</ul>
<li class="hide"><div class="caption" onclick="javascript:populate_menu(this)">Domain name</div>
<ul>
<li><a href="#">Free subdomain</a></li>
<li><a href="#">Free domin services</a></li>
<li><a href="#">Cheap domain registration</a></li>
</ul>
</div>
</body>
</html>

Now you can see the demo of the drop down menu here.

Adding hover effect with JavaScript

Now we have to add hover effect on the parent nodes to avoid any possible confusion on viewers mind in handling menu. To achieve it do the following steps.

  1. Change the cursor property of the 'caption' class to 'pointer' such that it looks like a link when mouse pointer is kept over a node.
  2. Define another css class 'caption_hover' with different background-color. When mouse pointer is kept over a node its css class will be changed to that class with the help of JavaScript. Add the following lines at the end of the style definition to define 'caption_hover' class.
Code | Download
#fw_nav .caption_hover{cursor:pointer;margin:0;color:#000000;font-weight:600; background:#cfd9ea url('arrow.gif') 3px center no-repeat;margin:0;border:none;border-top:1px solid #777777;font-weight:600;padding:5px 4px 5px 18px;}
#fw_nav .show div.caption_hover{background-image:url('down_arrow.gif');}

Now add two more JavaScript events onmouseover and onmouseout with the caption class division to see the hover effect.
<div class="caption" onclick="javascript:populate_menu(this)" onmouseover="this.className='caption_hover'" onmouseout="this.className='caption'">
Now you can see the demo of the drop down menu here.

JavaScript cookie to remember user setting

Up to this point your drop down menu is working quite nicely. But when you design menu for your entire website then you must keep some mechanism to remember and expand those nodes of a page which have already been expanded in earlier page. Say, your viewer open a page 'page1.html' and expand the nodes 'web hosting' and 'domain name'. Now he moves to a different page say page2.html. Here he will expect that the nodes which he already expanded on earlier page, i.e. page1.html, are kept expanded in current page too. This feature can easily be added with the help of cookie. Below I write three JavaScript function setmenu(), readmenu() and startmenu().
The function setmenu() stores the item indexes of the open nodes into a cookie file named 'adminmenu'. We have to call this function whenever viewer clicks a node to expand or to collapse it (i.e. at the end of the function populate_menu()). The function readmenu() reads cookie 'adminmenu' and return its value to the calling function. The function startmenu() play just opposite role to setmenu(). It reads cookie file expands the nodes whose item indexes are stored in cookie. We have to call this function after loading the document to restore viewer setting.

Code | Download
function setmenu()
var x=document.getElementById('nav').childNodes.length;
var str='';
for(var m=0; m<x; m++){
if(document.getElementById('nav').childNodes.item(m).className=='show'){if(str){str+='-';}str+=m;}
}
document.cookie = 'adminmenu'+"="+str;}
function readmenu(){
var arr = document.cookie.split(';');
for(var i=0;i < arr.length;i++){
var c = arr[i];
if (c.indexOf('adminmenu=') == 0) return c.substring(10,c.length);}
return 0;}
function startmenu(){
var menu_index=readmenu();
if(!menu_index){return;}
var menu_array=menu_index.split('-');
for(var i=0;i<menu_array.length; i++){
var c=menu_array[i];
if(document.getElementById('nav').childNodes.item(c)!=null){document.getElementById('nav').childNodes.item(c).className='show';}}}
More over we have to edit the function populate_menu() to call the function setmenu().
function populate_menu(i){
if(i.parentNode.className=='show'){i.parentNode.className='hide';}
else{i.parentNode.className='show';}
setmenu();}

Now we have to run the function start_menu() after loading the HTML document. Add the following JavaScript code just before the '</body>' tag of the HTML code.

Code | Download
<script type="text/javascript" language="javascript">
<!--
startmenu();
-->
</script>

In the above example I define style and JavaScript at the top of the document, i.e. between <head> and </head> tags. But in practice you should always use separate stylesheet and JavaScript file to reduce the size of the document. You can download the example page and all the necessary files associated with it from the link below.

Download sample code