YUI 2.8: Menus

Exclusive offer: get 50% off this eBook here
YUI 2.8: Learning the Library

YUI 2.8: Learning the Library — Save 50%

Develop your next-generation web applications with the YUI JavaScript development library

$26.99    $13.50
by Dan Wellman Daniel Barreiro | July 2010 | AJAX Open Source Web Development

In this article by Daniel Barreiro and Dan Wellman, authors of the book YUI 2.8: Learning the Library, we're going to look at a very common web page element: navigation menus. The Menu widget provides a timesaving and code-efficient solution to common website application requirements.

The skills that you will take away from this article include:

  • How to implement a basic navigation menu
  • How to override the default sam skin
  • How to create an application-style menu bar

(For more resources on YUI, see here.)

Common navigation structures

All but the most limited of websites must have a mechanism by which visitors can navigate around the pages of the site from the home page. In order to meet accessibility guidelines, several methods of navigation will usually be available, including at least a navigation menu and a site map.

There have been many different implementation styles that have been popular over the years. Before anyone really worried about accessibility or standards compliance, a common way of designing a navigation menu was to use a series of images that linked to other pages of the site, and there was also the popular frame-based navigation structure. While these methods saved the designer a lot of time, effort, and any real skill, they led to hugely increased page load times and a legacy of bad coding practice.

Thankfully, those days have long since passed, and with the continued development of CSS, it's now possible to design an effective navigation structure based on semantic HTML and styled with CSS.

Designing a navigation menu that is effective, robust, and presented effectively can still pose a challenge, and troubleshooting the compatibility of a menu between different browsers can be a very time-consuming process. This is where the YUI steps in.

Instant menus—just add water (or a Menu Control)

The Menu Control is used to add one of several different menus to your website, saving you the chore of adding this almost essential feature yourself. It's another control that takes a complex, difficult, or time-consuming task, and one which is an almost inherent requirement of any website, and packages it up into a convenient and easy-to-use module. The three different types of menu you can create are:

  • A standard navigation menu
  • An application-style menu bar
  • A right-click context menu

The navigation menu can be implemented as either a vertical or horizontal menu and generates a clean and attractive interface, which your visitors can use to navigate to different areas of your site. The navigation model of any site is key to whether using the site is easy and enjoyable; nothing turns off visitors more than a poorly designed or inconsistent navigation structure.

Another type of menu that the Menu Control is able to create is an application-style menu bar, which stretches across the screen horizontally, building on the current trend in the online world to blur the distinction between the browser and the desktop.

As well as taking care of navigation for you, it can also be used to add right-click context (pop-up) menus to any part of your web application, which again can give a web application a definite desktop feel to it.

The Menu Control is very flexible and can be built from existing HTML markup using a clean and logical list structure, or it can be generated entirely through JavaScript and built at runtime. Each of the different menu types is also given a default appearance with the sam skin so there is very little that is required to generate the attractive and highly functional menus.

We'll be looking at implementing each of the different types of menu ourselves in just a moment. Before we do this, let's take a quick look at the classes that go together to make the Menu Control.

The Menu classes

This component is made up of a small family of different types of menu. There is a range of different classes that work together to bring the functionality of the different types of menu to you.

The three main classes behind the Menu family are:

  • YAHOO.widget.Menu
  • YAHOO.widget.ContextMenu
  • YAHOO.widget.MenuBar

Menu is a subclass of Overlay, part of the Container family, and the other two are subclasses of Menu. Just as each TabView is made of several Tabs, each kind of Menu has a different class for its items:

  • YAHOO.widget.MenuItem
  • YAHOO.widget.ContextMenuItem
  • YAHOO.widget.MenuBarItem

ContextMenuItem is simply an alias for MenuItem created just for the sake of symmetry. All types of menu items can have a Menu as a submenu; neither ContextMenu nor MenuBar can be nested in a menu item, they are only good at the outermost level.

All the menus are coordinated by YAHOO.widget.MenuManager, which listens to events at the document body level and dispatches them to the corresponding menus or menu items using the technique of Event Delegation to the limit; after all, the document body is the furthest out an event can bubble.

Like the other members of the Container family, the constructor for Menu and its subclasses take two arguments; first a reference to existing markup or, if built via code, the id we want the Menu to have once rendered. The second argument takes the configuration options, if any, and accepts any configuration attribute as would be expected. However, in Menu, it can also take a couple of properties: itemData and lazyLoad, while MenuItem can also take value. We will see what they can be used for shortly.

Menus can be built from existing markup or from code or any combination of both. The required markup for a Menu might seem a little complicated at first but it is intended to work in older clients or for users without JavaScript enabled. This, we know, is called Progressive Enhancement and Menu supports it very well; the CSS style sheet for Menu works whether JavaScript is active or not and by using the correct class names the Menus will look just the same for all our visitors regardless of the capabilities of their browsers.

The markup will usually consist of a series of unordered lists <ul>, each of their list items <li> containing an anchor element <a> that leads to the next non-JavaScript enhanced page and optionally followed by a further nested unordered list. Menus will also read <select> elements creating a MenuItem for each <option>.

When building a Menu from code, we may create and add each individual MenuItem to the Menu or we may use the itemData configuration option we've just mentioned, which takes an object literal with the description of the whole Menu at once. This is particularly handy for ContextMenus as they hardly make any sense without JavaScript enabled.

Just as with any container, Menus have to be rendered. ContextMenus are usually rendered into document.body, as they have no place in the normal flow of the page. If the menu structure is too complex and takes too long to render, the lazyLoad option tells the Menu to render just the first level of items, those that would be visible initially, postponing rendering the rest until needed.

Menu subclasses

The ContextMenu is a specialized version of the control that provides a menu hidden from view until the element that it is associated with (the trigger element) is clicked with the right mouse button (except in Opera on Windows and OS X which requires the left-click + Ctrl key combination). The trigger element is defined using the trigger configuration attribute; this is the only configuration attribute natively defined by the ContextMenu class, all others are inherited.

The MenuBar is similar to the standard Menu, but is horizontal instead of vertical. It can behave like an application-style menu bar, where the top-level menu items must be clicked in order for them to expand, or it can behave more like a web menu where the menu items expand on a simple mouse over and have submenu indicators. This is controlled with the autosubmenudisplay Boolean configuration attribute.

The MenuItem class

Each menu type has a subclass representing the individual menu items that form choices within the menu. They will be created automatically when a Menu is built from existing markup or by setting the itemData configuration option to a menu description. You will only create individual MenuItems when extending the functionality of an existing menu.

MenuItems have several interesting configuration attributes:

  • checked: Shows a checkmark to the left of the label, useful for items that toggle in between two states.
  • classname: Added to the existing if any further styling is required. It can read this from existing markup.
  • disabled: This item cannot be selected and will be grayed out. When built from markup, it can read this attribute from an tag.
  • keylistener: The key combination (Shift, Control, or Alt + character) that will trigger this item. It can be read from markup.
  • onclick: The method to be called when this item is clicked.
  • text: A string to be shown in the label.
  • url, target: The destination page for this item when not handled via code.
  • selected: The item shows highlighted.
  • submenu: A nested instance of Menu, an object description of a nested Menu, or a reference to the markup that would produce it.
  • value: A value associated with this item.

MenuItem subclasses

The two subclasses YAHOO.widget.ContextMenuItem and YAHOO.widget. MenuBarItem both extend the MenuItem class, providing a constructor and some basic properties and methods for programmatically working with individual ContextMenu or MenuBar menu items.

As a matter of fact ConextMenuItem is simply an alias for MenuItem. MenuBarItem has different defaults than MenuItem to suit the different layout of the MenuBar.

Creating a Basic Navigation Menu

Let's put together a basic navigation menu.

Our menu will be built from underlying HTML rather than from script.

We'll be enhancing the example of the image portfolio by first providing a landing, home page that will welcome us. We'll later add a context menu to the image portfolio itself so that instead of adding an extra button (like Rate!) for each option, we'll handle them via menus. Once complete, our landing page should appear like this:

YUI 2.8: Learning the Library Develop your next-generation web applications with the YUI JavaScript development library
Published: July 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

(For more resources on YUI, see here.)

The initial HTML page

Menu requires yahoo-dom-events.js and container-core-min.js but, as our image portfolio example already contains the full container-min.js and all its dependencies, we just need to add menu-min.js and its corresponding CSS file, menu.css. A nice feature of the Dependency Configurator is that it can also provide us with a customized link to it with our selection set, such as this:

http://developer.yahoo.com/yui/articles/hosting/?container&MIN

We can save this URL in a comment in our page so that when we need to add extra components, we can start with this URL and then add the new ones. The Dependency Configurator will immediately notice that the full Container files are loaded and will avoid any duplication.

The layout of the image above was produced by this HTML:

<body class="yui-skin-sam">
<div id="doc" class="yui-t1">
<div id="hd">
<h1>DigitalDesigns</h1>
</div>
<div id="bd">
<div id="yui-main">
<div class="yui-b">
<h1>Welcome to DigitalDesigns!</h1>
<p>Lorum ipsum etc...</p>
<p>Lorum ipsum etc...</p>
</div>
</div>
<div class="yui-b">
<!-- the menu goes here -->
</div>
</div>
<div id="ft">
<p class="ftext">Copyright&copy; Mr Freelance 2007</p>
</div>
</div>
</body>

Except for the textual content in some of the sections this is a boilerplate grid with a narrow 160px sidebar on the left on a 750px document. It has been supplemented by some font choices, background coloring, and borders via CSS besides the styles provided by the sam skin. The menu will go where the highlighted comment shows. It was important to show this part of the HTML because it is easy to get lost once the markup for the menu is thrown in.

The underlying menu markup

There are two good reasons to create the main navigation menu from markup. The first is Progressive Enhancement because the markup Menu uses is perfectly workable for any visitor with even the most primitive browser. The second is to allow search engines to index our site. If we create the main menu via code, no search engine would be able to find the rest of the pages in our site.

We add the menu where the comment above shows:

<div id="navmenu" class="yuimenu">
<div class="bd">
<ul class="first-of-type">
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="aboutme.html">About Me</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="images.html">My Images</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="blog.html">My Blog</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="contact.html">Contact Me</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="imagelinks.html">Image Resources</a></li>
</ul>
</div>
</div>

We called it navmenu but any other name would do just as well. We do have to use the rest of the markup as shown. As Menu inherits from Overlay, it uses the standard SMF format, but it uses no head or footer so we just have a body bd section and in it, an unordered list (<ul>) where each list item is made of an actual link that should work both for old browsers and search engines and a label. All the class names are mandatory as the CSS file for Menu uses them, even the first-of-type class name, which signals that this is the top-level menu and not a submenu.

Our menu wouldn't be a proper navigation menu if there weren't, at least, a couple of submenus; it would just be a list of links. Let's add a couple of submenus now:

<div id="navmenu" class="yuimenu">
<div class="bd">
<ul class="first-of-type">
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="aboutme.html">About Me</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="images.html">Images</a>
<div id="images" class="yuimenu">
<div class="bd">
<ul>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="photography.html">Photography</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="fantasy.html">Fantasy Art</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="Corporate.html">Corporate Logos</a></li>
</ul>
</div>
</div>
</li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="blog.html">My Blog</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="contact.html">Contact Me</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="imagelinks.html">Image Resources</a>
<div id="links" class="yuimenu">
<div class="bd">
<ul>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="http://www.flickr.com">Flickr</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="http://www.b3ta.com">B3ta</a></li>
<li class="yuimenuitem"><a class="yuimenuitemlabel"
href="http://yotophoto.com">Yoto Photo</a></li>
</ul>
</div>
</div>
</li>
</ul>
</div>
</div>

The submenus take the same format as the top-level menu—an outer container <div> with a class of yuimenu forms the basis of the submenu, followed by an inner body <div>. Each submenu, like the overall Menu, is built from a standard unordered list (<ul>) element where each menu item is composed of a single list item (<li>). The structure of the menu is very similar to that of the overall page because it has a distinct body section (<div class="bd">) and can also be given hd and ft sections if required.

Formatting options

Menu offers a few formatting options. A menu or submenu may actually be made of several consecutive unordered lists. Menu will produce a thin dividing bar between each group.

A level-6 heading (<h6>) can be added before any <ul> to create a heading for each group; Menu won't mind any other heading level but the stylesheet has a suitable style only for an <h6>. The heading will be bold but slightly grayed out and it will not respond to a click.

When building the menu from code, these groups, whether with headings or not, can be created by using the optional groupIndex argument in .addItem() or .addItems(). Headers can be added with .setItemGroupTitle() using those same indexes. The .addItems() method, instead of a simple array of menu items, can also take an array of arrays of menu items, each nested array corresponding to a group.

Hints for keyboard shortcuts can be added to each item. Menu will not automatically respond to such shortcuts as read from the markup, a little more code is required afterwards, but the shortcut will be properly presented to the visitor. For example, in the code earlier we could have added a keyboard shortcut hint to an option by doing:

<li class="yuimenuitem">
<a class="yuimenuitemlabel" href="fantasy.html">
Fantasy Art<em class="helptext">Ctrl + F</em>
</a>
</li>

This image shows an assortment of such options:

The menu has been divided into three groups, each with its heading, the first two have keyboard shortcuts, and the second item is disabled. The My Blog option has the checked attribute set and the three items in the bottom submenu each have a class name so that they use the default icon (favicon.ico) from the target site as a non-repeating background image; the last site offers no default icon but should it offer one, the menu would immediately show it.

Menu will not automatically respond to the keyboard shortcut as displayed; it cannot parse it from the help text as that might be localized. The MenuItem object offers the keylistener configuration attribute that can be set to the key combination that will activate this item as if it had been clicked. This attribute uses the same format to describe the key combination as used by the YAHOO.util.KeyListener object of the Event Utility.

Creating the Menu object

Implementing a basic menu takes just a little bit of YUI-targeting JavaScript. You can add the following <script> block to the page directly above the closing </body> tag:

<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function() {
var menu = new YAHOO.widget.Menu("navmenu", {
position:"static" });
menu.render();
});
</script>

As soon as we detect the DOM is ready, we create the instance of Menu using the id of the markup as a reference and then we render it. We need to specify position as static because we want this menu to always be shown in the page, in contrast to dynamic menus that float over the contents. This is all we need; links in the terminal nodes of the Menu hierarchy will be active and navigate when clicked. Items having submenus will unfold the corresponding submenu but they won't navigate to the link destination, such links being reserved for non-JavaScript enabled browsers.

This way of navigating, though, is still too Web 1.0 style. Can we change the contents of the main panel without navigating at all? We can certainly do that. We will copy the main content of the image portfolio from the panel.html and paste it into the current content, enclosing each in its own <div>, like this:

<div id="yui-main">
<div class="yui-b">
<div id="welcome">
<a name="welcome"></a><h1>Welcome to DigitalDesigns!</h1>
<p>Lorem ipsum vix.</p><br>
<p>Nec no illud at ius.</p>
</div>
<div id="fantasyart">
<a name="fantasyart"></a><h1>Fantasy Art Images</h1>
<div class="images">
<img class="thumb" src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="images/image1_thumb.jpg">
<img class="thumb" src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="images/image2_thumb.jpg">
</div>
</div>
</div>
</div>

The content has been slightly clipped to fit in this page as signaled by the ellipsis. Now we have a welcome section and a fantasyart section. Each has an <h1> heading preceded by an anchor destination. The link in the menu item for this entry is also changed from href="fantasy.html" to href="#fantasyart". Thus, in a non-JavaScript situation, both sections would be visible and the link would serve to jump to that section. We then add the following code:


YAHOO.util.Event.onDOMReady(function() {
var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event;
Dom.setStyle("fantasyart","display","none");
var menu = new YAHOO.widget.Menu("navmenu", {
position:"static" });
menu.render();
menu.subscribe("click",function(type, oArgs) {
var ev = oArgs[0],
menuItem = oArgs[1];
switch (menuItem.cfg.getProperty("url")) {
case "#fantasyart":
Event.stopEvent(ev);
Dom.setStyle("welcome","display","none");
Dom.setStyle("fantasyart","display","");
menu.insertItem({text:"Home",url:"#welcome"},0);
break;
case "#welcome":
Event.stopEvent(ev);
Dom.setStyle("welcome","display","");
Dom.setStyle("fantasyart","display","none");
menu.removeItem(0);
break;
}
});
});

We are rendering the menu as we did before, but first we are hiding the fantasyart section so only the welcome section remains. We add a listener to the click event of the menu. We read both parts of the argument, the raw event object (ev) and the menuItem that was clicked. We read the url configuration attribute for that item and if it is #fantasyart we stop the propagation of the event (so it does not navigate on its own), toggle the visibility of both sections, and insert an extra item in the menu, which enables the visitor to return to the home page. This newly added menu item is the one handled in the next case where we reverse all we did in this one.

Adding menu items to a menu is easy as shown above. Methods .addItem() and .addItems() let us append new items to the end. These and .insertItem() take a freshly created instance of MenuItem (or the corresponding subclass for the other types of menu), a literal object with any configuration attributes, or a simple string to be used as the text attribute.

Summary

In this article,we looked at one of the most common parts of any website—the navigation structure. We also saw how to implement a basic navigation menu, how to override the default sam skin and also how to create an application-style menu bar.


Further resources on this subject:

YUI 2.8: Learning the Library Develop your next-generation web applications with the YUI JavaScript development library
Published: July 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Dan Wellman

Dan Wellman is an author and frontend engineer living on the South Coast of the UK and working in London. By day he works for Skype and has a blast writing application-grade JavaScript. By night he writes books and tutorials focused mainly on frontend web development. He is also a staff writer for the Tuts+ arm of the Envato network, and occasionally writes for .Net magazine. He's the proud father of four amazing children, and the grateful husband of a wonderful wife.

Daniel Barreiro

Daniel Barreiro, screen-name Satyam, has been a very active member in the YUI forums, providing support, writing articles in the YUI Blog, and maintaining examples and further articles in his own site. A YUI Contributor, he is one of the few external developers to have a component included in the YUI 2 library.

Books From Packt

jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Oracle Application Express 3.2 - The Essentials and   More
Oracle Application Express 3.2 - The Essentials and More

Yahoo User Interface 2.X Cookbook [RAW]
Yahoo User Interface 2.X Cookbook [RAW]

Tcl 8.5 Network Programming
Tcl 8.5 Network Programming

Moodle 1.9 for Teaching Special   Education Children (5-10): Beginner's Guide
Moodle 1.9 for Teaching Special Education Children (5-10): Beginner's Guide

Liferay Portal 6   Enterprise Intranets
Liferay Portal 6 Enterprise Intranets

Apache MyFaces 1.2 Web Application   Development
Apache MyFaces 1.2 Web Application Development

Firebug 1.5: Editing, Debugging, and   Monitoring Web Pages
Firebug 1.5: Editing, Debugging, and Monitoring Web Pages

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
9
n
b
n
C
4
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software