xMenu4 Horizontal - Cascading menus from nested ULs

I'm making changes to this... it may not work properly now.


This is still experimental. ;-)

Also have a look at the xMenu4 Vertical demo.

This code will turn a set of nested ULs into a cascading dhtml menu. It is completely downgradeable. Disable javascript and reload the page - you'll see the nested ULs (in the right column) with my downgrade CSS applied.

xMenu4 Template - this is the first implementation of this template. Give it a try. If you have ideas for improvement, please let me know.


v0.09, 7 Apr 05
xMenuManager did not support multiple menus - it was just a stub. Added xmObj to level 0 UL, implemented xMenuManager's mousemove listener and added a second menu for testing. Needs much testing. Thanks to Peter for reminding me :-)

v0.08, 21 Feb 05
Renamed files, changed colors, and provided an xMenu4 Template per Todd's request.

2 Mar 04
No changes to xMenu4.js, but I moved the menu to a page with a different layout and experimented with a few things - so it may be a little less cross-browser right now. There's plenty of tweaking that could still be done - but I'm tired of foolin with it for now ;-)

v0.07, 15 Jan 04
Now supports vertical positioning of main labels. Special thanks to Chris for helping with this.

v0.06, 3 Nov 03
Many improvements this time - rewrote the css and changed some menu code; found an Opera7 bug (130324); IE6's css-support gave me headaches.

v0.05, 27 Oct 03
Separated css and js into two files each. Tweaked css. The menu code now applies the styles on load, so the inline class names can be for downgrade mode. Improved downgrade styles - disable js and reload page to see it. Much remains to be done.

v0.04, 25 Oct 03
More tweaks. As a test I moved the UL to several different places in the html. It is now in one of the content DIVs.

v0.03, 24 Oct 03
Improved event handling and tweaked over-all design.

v0.02, 23 Oct 03
I rewrote the event handling and added A elements in each label element.


The js is in two files. One is for page-related js - the loader and onload listener, the other is the menu system code.

xmenu4.js - the menu system, don't rename and don't modify this file.

xmenu4_horizontal.js - your page onload code, rename this to the same as the html file. The contents of this file follow.

////--- Loader

if (!xIE4 && !xNN4) {
  document.write("<"+"link rel='stylesheet' type='text/css' href='xmenu4_dhtml.css'>");
  window.onload = xOnload;

////--- Load Event Listener

function xOnload()
  // Compatibility check
  var me = xGetElementById('myMenu1');
  if (!xDef(me.nodeName, me.firstChild, me.nextSibling)) {
  // myMenu1

  var mo = new xMenu4(
    me,                       // id str or ele obj of outermost UL
    true,                     // outer UL position: true=absolute, false=static
    true,                     // main label positioning: true=horizontal, false=vertical
    0, 1,                     // box horizontal and vertical offsets
    [-3, -10, -6, -10],       // lbl focus clip array
    [-30, null, null, null],  // box focus clip array
    // css class names:
    'xmBar', 'xmBox',
    'xmBarLbl', 'xmBarLblHvr',
    'xmBarItm', 'xmBarItmHvr',
    'xmBoxLbl', 'xmBoxLblHvr',
    'xmBoxItm', 'xmBoxItmHvr'


  // myMenu2

  mo = new xMenu4(
    'myMenu2',                // id str or ele obj of outermost UL
    true,                     // outer UL position: true=absolute, false=static
    true,                     // main label positioning: true=horizontal, false=vertical
    0, 1,                     // box horizontal and vertical offsets
    [-3, -10, -6, -10],       // lbl focus clip array
    [-30, null, null, null],  // box focus clip array
    // css class names:
    'xmBar', 'xmBox',
    'xmBarLbl', 'xmBarLblHvr',
    'xmBarItm', 'xmBarItmHvr',
    'xmBoxLbl', 'xmBoxLblHvr',
    'xmBoxItm', 'xmBoxItmHvr'


  xMnuMgr.load(); // calls the load method of all menus
  xmWinOnResize(); // initial positioning
  xAddEventListener(window, 'resize', xmWinOnResize, false);

////--- Window Resize Event Listener

function xmWinOnResize() // reposition the 2 menus on the page
  var me = xGetElementById('myMenu1');
  var rc = xGetElementById('rightColumn');
  var mm = xGetElementById('menuMarker');
  var mmp = mm.offsetParent;
  var x = xPageX(mm)-xPageX(rc);
  var y = xPageY(mm)-xPageY(rc);
  xMoveTo(me, x, y);
  me = xGetElementById('myMenu2');
  xMoveTo(me, x+220, y);
  xMnuMgr.paint(); // calls the paint method of all menus


The css is in two files. One supplies default and downgrade mode styles, the other supplies dhtml-related style rules.

xmenu4_default.css - default and downgrade styles, rename this to 'myPage_default.css'.

xmenu4_dhtml.css - dhtml-related styles, rename this to 'myPage_dhtml.css'.


No IDs are required, except for the outermost UL. The inline class names are for downgrade mode. Non-downgrade mode class names are passed to the menu object constructor. When Javascript and/or CSS are disabled the menu downgrades to standard nested ULs.

<ul id='myMenu1' class='myBar'> <!-- Begin myMenu1 -->

  <!-- Bar Label 1 -->

  <li><a class='myBarLblA' href=''>lbl-1</a>
    <ul class='myBox'>

      <li><a href=''>item 1-1</a></li>
      <li><a href=''>item 1-2</a></li>

      <li><a class='myBoxLblA' href=''>lbl-1-1</a>
        <ul class='myBox'>
          <li><a href=''>item 1-1-1</a></li>
          <li><a href=''>item 1-1-2</a></li>
        </ul> <!-- end box-1-1 -->
      </li> <!-- end lbl-1-1 -->

      <li><a class='myBoxLblA' href=''>lbl-1-2</a>
        <ul class='myBox'>
          <li><a href=''>item 1-2-1</a></li>
          <li><a href=''>item 1-2-2</a></li>

          <li><a class='myBoxLblA' href=''>lbl-1-2-1</a>
            <ul class='myBox'>
              <li><a href=''>item 1-2-1-1</a></li>
              <li><a href=''>item 1-2-1-2</a></li>
            </ul> <!-- end box-1-2-1 -->
          </li> <!-- end lbl-1-2-1 -->

        </ul> <!-- end box-1-2 -->
      </li> <!-- end lbl-1-2 -->

    </ul> <!-- end box-1 -->
  </li> <!-- end lbl-1 -->

  <!-- Bar Label 2 -->

  <li><a class='myBarLblA' href=''>lbl-2</a>
    <ul class='myBox'>

      <li><a href=''>item 2-1</a></li>
      <li><a href=''>item 2-2</a></li>

      <li><a class='myBoxLblA' href=''>lbl-2-1</a>
        <ul class='myBox'>
          <li><a href=''>item 2-1-1</a></li>
          <li><a href=''>item 2-1-2</a></li>

          <li><a class='myBoxLblA' href=''>lbl-2-1-1</a>
            <ul class='myBox'>
              <li><a href=''>item 2-1-1-1</a></li>
              <li><a href=''>item 2-1-1-2</a></li>
            </ul> <!-- end box-2-1-1 -->
          </li> <!-- end lbl-2-1-1 -->

        </ul> <!-- end box-2-1 -->
      </li> <!-- end lbl-2-1 -->

      <li><a class='myBoxLblA' href=''>lbl-2-2</a>
        <ul class='myBox'>
          <li><a href=''>item 2-2-1</a></li>
          <li><a href=''>item 2-2-2</a></li>
        </ul> <!-- end lbl-2-2 -->
      </li> <!-- end box-2-2 -->

    </ul> <!-- end box-2 -->
  </li> <!-- end lbl-2 -->

  <!-- Bar Item 1 -->

  <li><a class='myBarItmA' href=''>item-1</a></li>

</ul> <!-- end myMenu1 -->

Developer Support

We offer free DHTML developer support at the following forums. I hope you visit us.

SitePoint Javascript Forum

HFTOnline Webmastering Forum


By your use of X and/or CBE and/or any Javascript from this site you consent to the LGPL License - please read it. If you have any questions about the license, read the FAQ and/or come to the forums.