This post is the third in a series of tutorials exploring the steps necessary to build custom navigation menus in Oracle APEX. The first tutorial I wrote explains how you can create a jQuery accordion-like menu. In the second tutorial, I created a vertical collapsible menu in combination with a cookie mechanism to remember the state of each panel. These two menu types suffer from one serious restriction: the menu depth level is limited to a two-level hierarchy. The navigation menu in this article, however, supports an infinite depth level. This is how the end result looks like: demo.

Step 1: create a custom list template

Navigate to the template section of your current theme and create a list template from scratch. Assign it a name and a custom theme class. Then, edit the list template and copy and paste the following code snippets in the appropriate sections.

  • Before List Entry > List Template Before Rows (for example <table> <tr>)
<ul class="multiLevelMenu">
  • Template Definition > List Template Current
<li>
  <a href="#LINK#">
    #TEXT#
  </a>
</li>
  • Template Definition > List Template Current with Sublist Items
<li class="hasSubMenu">
  <a href="#LINK#">
    #TEXT#
    <div class="right-arrow"></div>
  </a>
</li>
  • Template Definition > List Template Noncurrent
<li>
  <a href="#LINK#">
    #TEXT#
  </a>
</li>
  • Template Definition > List Template Noncurrent with Sublist Items
<li class="hasSubMenu">
  <a href="#LINK#">
    #TEXT#
    <div class="right-arrow"></div>
  </a>
</li>
  • Before Sublist Entry > Sublist Template Before Rows
<ul class="multiLevelMenu subMenu">
  • Sublist Entry > Sublist Template Current
<li>
  <a href="#LINK#">
    #TEXT#
  </a>
</li>
  • Sublist Entry > Sublist Template Current with Sublist Items
<li class="hasSubMenu">
  <a href="#LINK#">
    #TEXT#
    <div class="right-arrow"></div>
  </a>
</li>
  • Sublist Entry > Sublist Template Noncurrent
<li>
  <a href="#LINK#">
    #TEXT#
  </a>
</li>
  • Sublist Entry > Sublist Template Noncurrent with Sublist Items
<li class="hasSubMenu">
  <a href="#LINK#">
    #TEXT#
    <div class="right-arrow"></div>
  </a>
</li>
  • After Sublist Entry > Sublist Template After Rows
</ul>
  • After List Entry > List Template After Rows (for example)
</ul>

Step 2: create and populate your navigation list

Create a list based on the list template we created in step 1 and include all navigation entries specific to your application. Remember that there is no limit whatsoever on the depth level.

The image below shows you a part of the list entries that I used for the demo:

list entries
list entries

Step 3: add the list to your pages

Page zero is ideal in this situation since you probably want to display the navigation menu on multiple pages. So just create a list region that uses the list we created in step 2.

Step 4: the CSS

Here’s how I styled my navigation menu in the demo:

/* first level menu */
ul.multiLevelMenu {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  line-height: 24px;
  list-style: none;
  background-color: #FFFFFF;
  width: 180px;
  border: 1px solid #444444;
  padding: 3px 0;
  -webkit-box-shadow: 0 5px 8px rgba(0,0,0,0.5);
  -moz-box-shadow: 0 5px 8px rgba(0,0,0,0.5);
  box-shadow: 0 5px 8px rgba(0,0,0,0.5);
}

div.right-arrow {
  display: inline-block;
  position: absolute;
  top: 50%;
  right: 8px;
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
  border-left: 3px solid #444444;
  margin-top: -3px;
}

ul.multiLevelMenu li {
  position: relative;
}
ul.multiLevelMenu li:hover {
  background-color: #3892FD;
}

ul.multiLevelMenu li a {
  display: block;
  padding-left: 6px;
  color: #444444;
  text-decoration: underline;
  cursor: pointer;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
}
ul.multiLevelMenu li a[href=""] {
  text-decoration: none;
}
ul.multiLevelMenu li a[href=""]:hover {
  cursor: default;
}

ul.multiLevelMenu li:hover > a {
  color: #FFFFFF;
  text-decoration: underline;
  border-top: 1px solid #2A6DBD;
  border-bottom: 1px solid #2A6DBD;
}
ul.multiLevelMenu li:hover > a[href=""] {
  text-decoration: none;
}
ul.multiLevelMenu li:hover > a div.right-arrow {
  border-left: 3px solid #FFFFFF;
}

/* sub level menus */
ul.subMenu {
  display: none;
}

.showSubMenu {
  position: absolute;
  top: -4px;
  left: 180px;
}

Step 5: include the hoverIntent jQuery plugin

The hoverIntent jQuery plugin is used to improve the usability of the navigation menu by introducing a short delay whenever the user unintentionally unhovers from a sub menu. Download the plugin here. Upload the jquery.hoverIntent.minified.js file as a static file in shared components and include it on your page(s) or page template.

#WORKSPACE_IMAGES#jquery.hoverIntent.minified.js

Step 6: the jQuery code

// global variables
var subMenuHoverConfig = {
  over : showSubMenu,
  timeout : 150,
  out : hideSubMenu,
  sensitivity : 15,
  interval : 150
};

// functions
function showSubMenu() {
  var subMenu = $(this).children("ul.subMenu");
  subMenu.show();
  subMenu.addClass("showSubMenu");
}

function hideSubMenu() {
  var subMenu = $(this).children("ul.subMenu");
  subMenu.hide();
  subMenu.removeClass("showSubMenu");
}

// page load
$(function() {
  $("ul.multiLevelMenu li.hasSubMenu").hoverIntent(subMenuHoverConfig);

  $("ul.multiLevelMenu a[href=\"\"]").click(function(event) {
    event.preventDefault();
  });
});

Put the above code in a file and upload it as a static file. Include it on your pages, just as you did for the hoverIntent jQuery plugin.

#WORKSPACE_IMAGES#multi-level-nav.js

Resources