Create a really simple fly-out menu
Recently I had a need to for a really simple menu to disclose some secondary options - you might think of it as a revealing interface.
There are a millions of flyout, drop down, suckerfish menu generators out there, but all of them are really complex. I just need to show a few options.
Here is what I came up with:
Instead of pasting a bunch of markup into this post, have a look at the live example.
How it works
The markup is super simple. There is a link used to trigger the menu, and the menu itself is an unordered list with some links it.
Scripting
The scripting is also very straightforward (I’m using jQuery, but there is nothing about it that is jQuery specific). Listen for a the .trigger link to get clicked, and display the closest .menu if it’s closed:
var $menu = $('ul.menu_options');
//hide all of the menus
$menu.hide();
$('a.trigger').each(function(index) {
$(this).click(function() {
//identify the clostest menu
$nextMenu = $(this).next($menu);
if ($nextMenu.is(":visible")) {
$nextMenu.fadeOut('fast').css('z-index', '50');
} else {
$menu.hide(); //close all other open menus
$nextMenu.show().css('z-index', '500'); //z-index for good measure
}
return false;
});
});
That’s probably good enough for most uses - but I can’t leave good enough alone. The weakness with is that the menu hangs around until you click the trigger again to close it.
Here is the ideal behavior:
- If you trigger the menu and do nothing, it will go away after n seconds.
- If you trigger the menu and mouseover it, it will stay there.
- When you mouse leaves the menu, it will go away after n seconds.
To achieve this, we’ll set a unique setTimeout for each menu and listen for mouseenter and mouseleave events to clear the timeout. Here it is all together:
var $menu = $('ul.menu_options');
var $open = $('a.trigger');
//create an emtpy object to keep track of the timeouts
var menuTimeouts = {};
//hide all of the menus
$menu.hide();
$open.each(function(index) {
$(this).click(function() {
//identify the clostest menu
$nextMenu = $(this).next($menu);
if ($nextMenu.is(":visible")) {
$nextMenu.fadeOut('fast').css('z-index', '50');
//clear the active setTimout
if (menuTimeouts[$id]) {
clearTimeout(menuTimeouts[$nextMenu.attr('id')]);
menuTimeouts[$nextMenu.attr('id')] = undefined;
}
} else {
$menu.hide(); //close all other open menus
$nextMenu.show().css('z-index', '500'); //z-index for good measure
//start a unique setTimeout for this menu
menuTimeouts[$nextMenu.attr('id')] = setTimeout(function () {
//fade the menu out after 2 seconds
$nextMenu.fadeOut('slow');
}, 2000)
}
return false;
});
});
$menu.find('li').mouseenter(function (event) {
//store the ID of this trigger's closest menu
var $id = $(this).parents('ul').attr('id');
//cancel the timeOut when the mouse is over the menu
if (menuTimeouts[$id]) {
clearTimeout(menuTimeouts[$id]);
menuTimeouts[$id] = undefined;
}
}).mouseleave(function () {
var $this = $(this).parents('ul');
//start another time when the mouse leaves the menu
menuTimeouts[$this.attr('id')] = setTimeout(function () {
$this.fadeOut('slow');
}, 2000);
});
Checkout live example to see it all in action →
I’ve tested this in Firefox, Safari, and IE7 and IE8. You might need to tweak the position of the menu in IE, but everything else is good to go.

Wade Winningham said:
Nice! I could see this being used like those new iPad pop-overs.
Steve Brewer said:
Nice! I think you’re point about simplicity is good. The generic systems support a lot of use cases, but are really complicated. If what you need is simple, then a simple solution works well.
Delicious Bookmarks for March 5th through March 6th « Lâmôlabs said:
[…] Create a really simple fly-out menu | Travis Isaacs | My Life In Pixels – March 6th ( tags: jquery fly-out menu webdesign navigation tutorial web webdev javascript js example ) […]