Вот накатал на чистом JS, проверил в IE6 и Firefox 3.6
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
#menu li {
display:inline;
margin:10px;
}
li.hasUl {
list-style-image:url(plus.gif);
}
li.hasUl li {
list-style-image:none;
}
#list1 {
display:block;
}
#list2 {
display:none;
}
</style>
</head>
<body>
<ul id="menu">
<li id ="menu1">Menu 1</li>
<li id ="menu2">Menu 2</li>
</ul>
<ul id="list1">
<li class="hasUl">Item 1
<ul>
<li>Item 1.1</li>
<li>Item 1.2</li>
<li>Item 1.3</li>
<li>Item 1.4</li>
</ul>
</li>
<li class="hasUl">Item 2
<ul>
<li>Item 2.1</li>
<li>Item 2.2</li>
<li>Item 2.3</li>
<li>Item 2.4</li>
</ul>
</li>
<li class="hasUl">Item 3
<ul>
<li>Item 3.1</li>
<li>Item 3.2</li>
<li>Item 3.3</li>
<li>Item 3.4</li>
</ul>
</li>
</ul>
<ul id="list2">
<li class="hasUl">Item 4
<ul>
<li>Item 4.1</li>
<li>Item 4.2</li>
<li>Item 4.3</li>
<li>Item 4.4</li>
</ul>
</li>
<li class="hasUl">Item 5
<ul>
<li>Item 5.1</li>
<li>Item 5.2</li>
<li>Item 5.3</li>
<li>Item 5.4</li>
</ul>
</li>
<li class="hasUl">Item 6
<ul>
<li>Item 6.1</li>
<li>Item 6.2</li>
<li>Item 6.3</li>
<li>Item 6.4</li>
</ul>
</li>
<li>Item 7</li>
</ul>
<script>
if(document.getElementsByClassName) {
getElementsByClass = function(classList, node) {
return (node || document).getElementsByClassName(classList)
}
} else {
getElementsByClass = function(classList, node) {
var node = node || document,
list = node.getElementsByTagName('*'),
length = list.length,
classArray = classList.split(/\s+/),
classes = classArray.length,
result = [], i,j
for(i = 0; i < length; i++) {
for(j = 0; j < classes; j++) {
if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
result.push(list[i])
break
}
}
}
return result
}
}
function addEvent(elem, type, handler){
if (elem.addEventListener){
elem.addEventListener(type, handler, false)
} else {
elem.attachEvent("on"+type, function() { handler.call(elem)})
}
}
function processLi(event) {
event = event || window.event;
var target = event.target || event.srcElement;
if (this == target)
{
var childs = this.getElementsByTagName('li');
var style;
for (var i = 0; i < childs.length; i++) {
if (childs[i].style.display == "none") {
childs[i].style.display = "block";
if (i == childs.length - 1) this.style.listStyleImage = "url(minus.gif)"
}
else {
childs[i].style.display = "none";
if (i == childs.length - 1) this.style.listStyleImage = "url(plus.gif)"
}
}
}
}
function processFirstList() {
var list1 = document.getElementById("list1");
var list2 = document.getElementById("list2");
var style;
if (window.getComputedStyle) {
style = window.getComputedStyle(list1, null);
}
else {
style = list1.currentStyle;
}
if (style.display == "none")
{
list2.style.display = "none";
list1.style.display = "block";
}
}
function processSecondList() {
var list1 = document.getElementById("list1");
var list2 = document.getElementById("list2");
var style;
if (window.getComputedStyle) {
style = window.getComputedStyle(list2, null);
}
else {
style = list2.currentStyle;
}
if (style.display == "none")
{
list1.style.display = "none";
list2.style.display = "block";
}
}
addEvent(document.getElementById("menu1"), "click", processFirstList);
addEvent(document.getElementById("menu2"), "click", processSecondList);
var liElements = getElementsByClass("hasUl");
for (var i = 0; i < liElements.length; i++) {
addEvent(liElements[i], "click", processLi);
var li = liElements[i].getElementsByTagName('li');
for (var k = 0; k < li.length; k++)
li[k].style.display = "none";
}
</script>
</body>
</html>