type: widget
release: 1.9
status: in development
documentation: http://docs.jquery.com/UI/Menu
demo: http://view.jqueryui.com/master/demos/menu/default.html
TODOs:
- Add dividers via empty menu items or unlinked menu items with text
- visual test: menu with checkbox, radio and text inputs
- Until extensions are housed with jQueryUI see http://kborchers.github.com/jquery-ui-extensions/menu/inputmenu.html
- Add placeholder demo that links to this demo so we don't lose it
- Write unit tests
- Write documentation
1 - Description:
Transforms a (nested) list into a themeable menu with mouse and keyboard interactions for navigation.
NOTE: numbers in brackets reference visual designs.
Flat, non-hierarchical list (default when there are no nested lists)
- simple menu [D1] appears/acts like a customized dropdown list.
- popup menu [D8] appears/acts like a native Mac OS select list, where the the selected option appears boxed to the left of the trigger button, and the user can click either the selected option or button to open the menu. The menu is positioned so that the selected option always appears at the same place in the list; when the menu is open, if the selected option is third from the top, you'll see the first two options above the selection, and the rest below.
Hierarchical list:
- fly-out [D2 and D3], if the option is explicitly set or, as a best practice, if number of sub-levels limited to 2 or 3 (when 3+ submenus are showing, collision detection can become unwieldy depending on the available space in the viewport). Behaves similarly to Apple's OS menus where the main menu appears on click and sub-menus on hover; the current sub-menu remains open as long as the user's mouse is over it, otherwise it (and any other sub-menus) closes after a short delay. The user's path through the menu is marked with an "on" state.
- ipod-style/drilldown [D6 and D7], if the number of sub-levels is larger or unknown or if the option has been explicitely set. Mimics its namesake by showing a main menu, and as you choose options that navigate to deeper levels, the next menu slides to the left into view. By default a "back" link appears at the bottom of the menu, and when clicked, the visible menu slides to the right out of view. Options allow the user to:
- show a full breadcrumb in place of the back link
- change the location of the back link (above vs. below the menu)
- change the default back text (from "Back" to something else)
- set default breadcrumb text (i.e., "Choose an option:")
- select wether the menu should be context loaded, drop down or statically rendered
- menubar [E2], if the option is explicitly set (not automatic detection): the top-level menu options are arranged either horizontally or vertically in a row, and sub-menus appear either below or beside them, respectively. Sub-menus can be formatted as flat, ipod-style, or flyout. This menu could be used as standard global navigation, or as part of a toolbar. (The toolbar is a separate widget that groups navigation and form controls.) -> This is covered by the Menubar widget.
Split buttons
Users should have the option to create split-buttons for any menu option, where the left button selects the node and the right button opens a sub-menu. The original design only spec'd split buttons for ipod style menu, but this could be useful to show link affordance in fly-outs as well.
Check and radio options
- a check or radio option is always a leaf node, never has a child menu
- check options can be toggled on/off one at a time; multiple check options can be selected/on in a single menu
- radio options are like their namesake in that you can choose one from a group. Example: EXT toolbar, "button with menu:" http://extjs.com/deploy/dev/examples/menu/menus.html
- radio options must be visually grouped together, either in a stand-alone menu or sub-menu, or set apart from other list items with a divider
- when one or more options has an check, radio, or custom icon, the entire menu -- parent menu plus all sub-menus -- is indented left so that the icons are easily scannable in a left "column"
Custom icons [D5]
Users could also specify unique icons that appear next to particular menu options.
Dividers
- dividers could be specified in the original (pre-menu widget) markup as:
- an empty list item. The menu widget could insert a horizontal rule for vertical menus, or a vertical rule for horizontal menus (menubars)
- a list item containing text (not linked) could be converted to a horizontal rule followed by a text label
- dividers/labels are not clickable
Sub-menu indicator arrows and icon alignment [D4]
- for vertical menus: Arrow icons which indicate sub-menus always appear in the right column. It may be problematic to flip the location of the arrows to the left side of the menu; doing so would only work when there are no left column check/radio icons, otherwise it may be visually noisy. Keeping the arrow icons on the right but flipping their direction to point left may also be confusing, as the arrow would be pointing back to the list item -- has anyone seen a menu behave this way? Using the Mac OS default behavior as a guide, it may be a safer bet to never flip the location or direction of the arrows and have them always stay in the right column and point right, which is the default direction of the menu, and reserve the left column for icons.
- for horizontal menus (top-level menubar buttons): An option could be set whether to show a "down" arrow to indicate sub-menus.
As decribed in the first paragraph, the behaviour/mode of the menu can be set to the following (the option for this is called 'mode'):
- dropdown, makes the element the menu is bound to to act like a button, therefore drops down the menu to one side of the original element (default is below, configurable via option 'direction')
- context, appears on right-click in a specified region by default, or the user can optionally make it appear on left click or a key + click combination [any suggestions for this option?]. The direction option can be used to set how it pops up, the default is "right below".
- static (default), simply takes the list or JSON and renders the menu statically (always visible) into the original element. If you don't specify the items option, it will search for the first ul that is a child of the selected element and transforms it automatically (this is specific to the selected mode).
One thing to consider for the grid (and many other future UI plugins) is that HTML 5 provides detailed specs for these widgets that we should seriously consider using as a blueprint for our plugins. If we shared similiar naming and conventions, it will provide a cleaner interface in the future when we all have to support both the HTML 5 version (where available) and the JS-based UI plugin verison on the same site (i.e. use the native HTML 5 if availble, fall back to JS if not supported). The other benefit is that these specs have been refined by a large group of people so they are fairly mature and there may be no need to reinvent the wheel. There is a menu spec here:
http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#menus
Many, many jQuery menu plugins already exist that we may be able to mine for ideas, or use as the basis for the jQuery widget. Several are listed below, but there may be others that look as/more promising (feel free to add to or edit this list):
Single or multi-level menus (dropdown, flyout, ipod-style)
Context menu
Enhance standard <select> into menu
http://www.givainc.com/labs/linkselect_jquery_plugin.htm
Filament flyout and iPod menus with ARIA and CSS framework support:
http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/
http://www.filamentgroup.com/examples/menus/index.html
http://filamentgroup.com/examples/menus/ipod.php
iOS-Style menu build on jQuery UI 1.9's menu widget:
http://jamesarosen.github.com/jquery-ui/demos/menu/ios-menu.html
Themeroller-based drilldown menu: http://www.matthewfeerick.com/jquery_menu/
For a very detailed description of menu design best practices and behavior, please review the Apple's UI guidelines for menus or Microsoft's Vista UI guide for menus.
Menubar ARIA example implementation that includes inputs: http://oaa-accessibility.org/examplep/menubar1/
Dojo/Dijit Menu, Menubar, Contextmenu: http://archive.dojotoolkit.org/dojo-2011-07-12/dojotoolkit/dijit/tests/test_Menu.html
2 - Visual Design:

3 - Functional Specifications/Requirements:
Options:
- menus String containing the tag name used for menu elements, default: "ul"
- position (Options or Function, default: { my: "left top", at: "right top", of: active-item } )
- How to position nested menus relative to the parent menu
- Override with any of the Position options to customize
- Override with function that returns the full set of Position options to specify the relative element. Gets the current list item as the only argument. Use of: item.parent() to get top-alignment.
Methods:
- refresh
- Renders all non-menu-items as menu-items, called once by _create
- Matches all li-elements with a child a-element, adds a class of ui-menu-item to each li that doesn't yet have that class
- Call whenever adding or replacing items in the menu via DOM operations,
e.g. via menu.append("<li><a href='#'>new item</a></li>").menu("refresh")
- focus(event, item)
- focus an item (jQuery object wrapping a li-element), by: blur the current item, scroll the new one into view if necessary, make it the focused item, and triggering the menu's focus event
- if there is no original event, pass null instead
- blur(event)
- Clear the current focus
- Useful when reopening a menu which had previously an item focused
- next(event)
- Focus the next item based on the focused one
- Focus the first if
- none is focused
- the last one is focused
- previous(event)
- Focus the previous item based on the active one
- Focus the last if
- none is focused
- the first one is focused
- nextPage(event)
- Similar to next, but jumps a whole page
- prevPage(event)
- Similar to previous, but jumps a whole page
- collapse(event)
- Focus a parent menu, if any.
- expand(event)
- Open and focus a sub menu of the currently focused menu item, if any.
- closeAll
- Close all open sub menus and blur them.
- select(event)
- Select the focused item, triggering the select event for that item
- Useful for custom keyboard handling
Events:
- All events have ui.item refer to a jQuery object containing the focused menu item (a li-element)
- focus
- Triggered when a menu item gets mouse (on hover) or keyboard (navigation with cursor keys) focus
- blur
- Triggered when a menu item loses focus
- select
- Triggered when a menu item was selected
There is no API for binding data to each item that menu provides. Instead, jQuery's data API can be used to bind whatever necessary to each menu item and retrieve that within the select-event via ui.item. Autocomplete does exactly that.
Delaying opening and closing submenus
When hovering a menu item with a submenu, slightly (200-300ms) delay opening the submenu. Close open (sibling) submenus when opening another submenu.
Implementation-wise: Start a timeout on mouseover. Clear the timeout on mouseout. When it executes, close open submenu and open the new submenu.
Icons
Icons are supported by adding a class of ui-menu-icons to the menu element, which happens automatically when there is an element within the menu with the class ui-icon. The ui-menu-icons class adds some padding to the left to offset menu items (with or without icon). The icon generated for submenus isn't affected and will continue to be positioned on the right.
4 - Markup & Style:
4.1 Initial markup examples
Any unordered list:
<ul>
<li><a href="/http://google.com">Google</a></li>
<li><a href="/http://yahoo.com">Yahoo</a></li>
<li><a href="/http://msn.com">MSN</a></li>
<li><a href="/http://ask.com">Ask</a></li>
<li><a href="/http://aol.com">AOL</a></li>
</ul>
For nested menus, nested unordered lists:
<ul>
<li><a href="/http://google.com">Google</a></li>
<li><a href="/http://yahoo.com">Yahoo</a></li>
<li><a href="/http://msn.com">MSN</a>
<ul>
<li><a href="/htp://sub1.example.com">sub-level</a></li>
<li><a href="/http://sub2.example.com">sub-level</a></li>
</ul>
</li>
<li><a href="/http://ask.com">Ask</a></li>
<li><a href="/http://aol.com">AOL</a></li>
</ul>
4.2 Recommended transformed HTML markup
4.3 Accessibility recommendations
Set role="listbox" on menu container (usually ul).
Set aria-activedescendant attribute with the value referring to the current active item's id-attribute, which, if not present, gets generated based on the menu's id and a "-activedescendent" postfix.
Set role=menuitem to items in the menu, and add aria-haspopup=true for items that have a submenu.
4.4 CSS & Theme
See implemented jquery.ui.menu.css
5 - Latest version of plugin:
http://view.jqueryui.com/master/tests/visual/menu/menu.html
6 - Open issues being discussed
API Challenges
While working on the iOS-style version of the menu, I found I needed to redefine several key methods:
- #left - the default behavior simply hides the menu and focuses on the parent; I needed to slide the child out.
- #_open - the default behavior shows and positions the child menu; I needed to position it, then slide it in.
- #select - I added back links to the child lists and thus had to override #select to call #left instead of triggering a select event
- #_startOpening - the default behavior is to show a submenu when hovering over (or focusing via keyboard navigation) its name; this doesn't work for the iOS-style menu, which relies on an active press (mouse or keyboard) to open a menu
In general, this can all be overcome by splitting out behavior into smaller helper methods that are configurable via options(). I rather like the SproutCore- and Cocoa style of willFoo() and didFoo() callbacks. For example, we could add a willMoveLeft(event, parent, child) and didMoveLeft(event, parent, child) callbacks. If willMoveLeft returns false, the move is cancelled. [James]
The jQuery UI pattern for naming cancelable and notification events (like this) is beforemoveleft and moveleft. For example, see Dialog's beforeclose and close. [Richard]
@James: Can you look into splitting out the internal functionality of the existing methods into smaller methods so you can just override the individual parts you care about? For example, you could move the position/show code into its own function and change that to do the positioning and sliding. You can also look at the custom tooltip animation demo (see the open event example) to see how the animations for menu might be possible even without refactoring the base menu. For the back button, can you add a header above the menu and put the back button up there? That would be more like the iOS implementation. [Scott]
Issue where mouseover of the menu to open submenus does not allow for keyboard navigation of the menu or submenus
- Need a use case from the desktop to prove a need for this to be fixed.
Inputs Menu
All work for input menu has been moved to an extension here https://github.com/kborchers/jquery-ui-extensions/tree/master/menu with a demo here http://kborchers.github.com/jquery-ui-extensions/menu/inputmenu.html
Comments (8)
fnagel said
at 5:35 pm on Oct 18, 2011
There are some issues in IE6 and IE7. Menus with overflow have two scollbars. This could be fixed by using: .ui-menu .ui-menu-item { width: auto; }
Another problem is some moving when hovering items with a sublevel.
Tested with VM with MS Images (WinXP IE6 and WinVista IE7) and the demo file provided here: http://view.jqueryui.com/master/tests/visual/menu/menu.html
sosensible said
at 9:32 am on Nov 1, 2011
Are we taking mobile into account on these tools? (menu and toolbar?) for tablets and phones.
Scott González said
at 10:23 am on Nov 1, 2011
We're just starting to work on touch support, which is scheduled for the 2.0 release. We're starting with the new interaction plugins and then we'll be expanding to the widgets.
Jörn Zaefferer said
at 12:32 pm on Dec 6, 2011
Menu feedback on the forum: http://forum.jquery.com/topic/jquery-ui-menu-comments#14737000002907084
Alex Barker said
at 7:35 pm on Dec 10, 2011
Has anyone tired adding a .ui-state-highlight to .ui-menu .ui-menu-item a ? I keep trying to get it in there, but the borders and margins keep fighting. If i set the margin to -1 on the highlight class the hover on the menu items above and below the highlighted item find a way to insert it back in. I have no idea why.
sievlev said
at 8:56 am on Feb 6, 2012
The only way to disable menu items is to use 'ui-state-disabled' class. But menu items marked as 'ui-state-disabled' are still available via keyboard.
Kris Borchers said
at 3:16 pm on Feb 6, 2012
OK, I have updated this functionality with this commit https://github.com/jquery/jquery-ui/commit/87dc9ce24a6355ea551b9dfc266b84712fd5d00c. Please feel free to test and provide feedback.
Kris Borchers said
at 9:53 am on Feb 6, 2012
Good catch. I will get this fixed ASAP. Thanks!
You don't have permission to comment on this page.