jQuery Context Menu Plugin

A context menu plugin for jQuery that features easy implementation, keyboard shortcuts, CSS styling, and control methods.

Contents

Overview

jQuery Context Menu is a context menu plugin for jQuery. It was designed to make implementing context menu functionality easy and requires minimal effort to configure.

There is another context menu for jQuery written by Chris Domigan. These two projects are completely unrelated and no source code was shared from Chris’ project.

Why reinvent the wheel? The goal of this plugin is to streamline the way actions are binded to menu items and to use 100% CSS for styling. Keyboard shortcuts were added for navigating the menu once it’s open, and there are five methods to allow you to control and clean-up context menus on the fly.

Features

Compatibility

jQuery Context Menu works in all browsers supported by jQuery. It has been fully tested in:

*Opera 9.5 has an option to allow scripts to detect right-clicks, but it is disabled by default. Furthermore, Opera still doesn’t allow JavaScript to disable the browser’s default context menu which causes a usability conflict.

Demo

View a live demonstration of the context menu plugin.

Download

Current version: Version 1.0 (14 September 2008)

This plugin is provided to you as-is, at absolutely no cost. If you would like to support its development, feel free to contribute any amount you prefer via PayPal. As always, you are welcome to contribute code for bug fixes and feature enhancements as well. Either way, thanks for supporting our efforts!

Usage

Dependencies

jQuery Context Menu requires jQuery 1.2.6 or above (or jQuery 1.2 with the dimensions plugin).

Creating

First, create a list in your HTML that will be the markup for your context menu:

<ul id="myMenu" class="contextMenu">
    <li class="edit">
        <a href="#edit">Edit</a>
    </li>
    <li class="cut separator">
        <a href="#cut">Cut</a>
    </li>
    <li class="copy">
        <a href="#copy">Copy</a>
    </li>
    <li class="paste">
        <a href="#paste">Paste</a>
    </li>
    <li class="delete">
        <a href="#delete">Delete</a>
    </li>
    <li class="quit separator">
        <a href="#quit">Quit</a>
    </li>
</ul>

Actions are specified in the href attribute, preceeded by a # symbol. When selected, this is what will be passed back to the action parameter in the callback. You can add class attributes to the list items to assist with styling, but they have no functional meaning. Thus, class names do not have to correspond with actions.

Once you have created the markup for the context menu, bind it to one or more elements using JavaScript:

$(document).ready( function() {
   
    $("#selector").contextMenu({
        menu: 'myMenu'
    },
        function(action, el, pos) {
        alert(
            'Action: ' + action + 'nn' +
            'Element ID: ' + $(el).attr('id') + 'nn' +
            'X: ' + pos.x + '  Y: ' + pos.y + ' (relative to element)nn' +
            'X: ' + pos.docX + '  Y: ' + pos.docY+ ' (relative to document)'
            );
    });
   
});

Make sure you change #selector to the appropriate jQuery selector that matches the element(s) you want to bind the context menu to. The selector can be any valid jQuery selector.

Methods

There are five methods you can use to control and clean-up the context menu after it has been instantiated.

MethodDescription
disableContextMenu() Disables the context menu on all matching elements
enableContextMenu() Re-enables the context menu on all matching elements
disableContextMenuItems('#option1,#option2,...') Disables the specified options on all matching elements. If null is passed, all elements will be disabled.
enableContextMenuItems('#option1,#option2,...') Enables the specified options on all matching elements. If null is passed, all elements will be enabled.
destroyContextMenu() Unbinds the context menu from all matching elements

As an example, to disable the context menu on a div with an ID of myDiv the code would look like this:

$("#myDiv").disableContextMenu();

Styling

The context menu relies 100% on CSS for styling. To give your users an aesthetically pleasing experience, you should either use the included stylesheet or create your own. Refer to jquery.contextMenu.css to make any changes in the styles.

Callback

The callback function fires if and only if a user makes a valid selection from the context menu. Three arguments are passed which you can use to control what happens when a user makes a selection:

ParamterDescription
action The action that corresponds to the menu item that was selected (I.E. the href attributes less the # symbol)
el The element object that triggered the context menu
pos.x Horizontal position of mouse cursor when menu was clicked (relative to the element)
pos.y Vertical position of mouse cursor when menu was clicked (relative to the element)
pos.docX Horizontal position of mouse cursor when menu was clicked (relative to the document)
pos.docY Vertical position of mouse cursor when menu was clicked (relative to the document)

See the example above for starter code.

Licensing & Terms of Use

jQuery Context Menu is licensed under a Creative Commons License and is copyrighted ©2008 by Cory S.N. LaViska.

Comments

Does not for on my FF3.0.1 ... it works on IE7 ...

#1 Hans on Sep 16th, 2008

@Hans: Do you happen to have the All-in-One mouse gestures plugin? If so, try disabling it - it seems to conflict with right-click events. A better plugin that doesn't conflict is Mouse Gestures Redox (https://addons.mozilla.org/en-US/firefox/addon/39).

#2 Cory S.N. LaViska on Sep 16th, 2008

How i can find the option which allows scripts to detect right-clicks in Opera?

#3 vladm on Sep 17th, 2008

@vladm: In Opera 9.5, Tools > Preferences > Advanced > Content > JavaScript Options.

#4 Cory S.N. LaViska on Sep 17th, 2008

Do You plan fixing for well known IE5-6 bug, that makes visible select boxes "holes" if context menu (and any z-indexed div) overlaps them ? (Usually iframes are used to fix it)

#5 Alexander on Sep 22nd, 2008

Nice work Cory! :)

#6 James on Sep 22nd, 2008

This is great. It was easy to setup and use, the styling and functionality is almost what I need.

I'm using a Canvas tag and I need to present a different menu depending on where the user is in the tag. So I added in this functionality, you can specify a 'chooseMenu' function which gets given the coordinates structure and can return which menu to show.

Patch is here (http://www.xb95.com/contextMenu.diff) in case your interested. Caveat lector, of course, I'm pretty new to JS and jQuery. My changes work in my app but not certain if they are 'correct' or not. :)

#7 Mark Smith on Sep 27th, 2008

This is great! It works like a champ!

I've only small issue: when context menu is displayed, it seems to disable onClick event handlers on the whole page. Did I anything wrong? How can I work around this?

#8 Piotr Findeisen on Sep 30th, 2008

@Piotr: you're right, the plugin binds a click event to the document and then unbinds it when the menu is removed. You could work around this by creating an overlay that covers the entire screen and bind the click event to that. I'm really interested to see what people think would be the best way to handle this as, in your case and most likely others, the current behavior can cause interference.

#9 Cory S.N. LaViska on Sep 30th, 2008

@Cory: you can take a look at jQuery Modals http://dev.iceburg.net/jquery/jqModal/ -- the implement overlay that doesn't interfere with my custom onClick events.

#10 Piotr Findeisen on Sep 30th, 2008

@Cory: i've a patch that "works for me". There is still an issue with "destroyContextMenu" -- it unbinds to many handlers (example: I have <a> element with custom onClick event and context menu...)
Want me to post the patch here (99 lines or so)?

#11 Piotr Findeisen on Oct 8th, 2008

Great idea, but doesnt work to well in my Safari (3)... need to click and right click several times before a menu pops up???

#12 Paul on Oct 15th, 2008

I have a small problem - on IE7 I get actions like "ttp:/../../xx#cut". I can cut off the first part of the string in my application - but I probably is doing something wrong. I do not see this when running your demo - here action is "cut" etc.

#13 Lisbeth on Oct 16th, 2008

@Paul: would you mind submitting some code, if possible? I have it running in a few apps and can't replicate the clicking issue in Safari 3.

@Lisbeth: Sounds like your href attribute is wrong. It should only be something like #cut, #copy, etc., not a full URL.

#14 Cory S.N. LaViska on Oct 16th, 2008

Hello Cory,
what about sub-menus. Are they supported? Could you posible add a sub-menu example?

#15 Martin on Oct 17th, 2008

@Martin: Submenus are not currently supported, but will be in the next version.

#16 Cory S.N. LaViska on Oct 17th, 2008

Hello Cory,

Do you have a delay about the submenu feature ? :'-)
Because I need this feature to use your plugin.

I don't want speed you ^^

#17 oxman on Oct 19th, 2008

Does this have to be bound? Can this be set to activate no matter where they right click on the site?

#18 Rob on Oct 20th, 2008

#Rob: currently it has to be bound, but you raise a good point. It may be worthwhile considering a way to trigger the menu if the right click occurs period. You can probably add an event listener yourself to accomplish this without much difficulty.

#19 Cory S.N. LaViska on Oct 20th, 2008

Good work, but I have some problems to detect witch item is clicked.

my html code is like this:
<ul id="items">
<li id="item1"><a href="#">Item 1</a>
<ul>
<li id="item1-1"><a href="#">Item 1.1</a></li>
</ul>
</li>
</ul>

So where I right click on item 1.1 and chose the menu i want to get the id of that item, in this case "item1-1". How can I do this?

Her is my JS:
$("#items").contextMenu({
menu: 'myMenu'
}, function(action, el, pos) {
alert(
'Action: ' + action + '\n\n' +
'Element ID: ' + $(el).attr('id') + '\n\n' +
'X: ' + pos.x + ' Y: ' + pos.y + ' (relative to element)\n\n' +
'X: ' + pos.docX + ' Y: ' + pos.docY+ ' (relative to document)'
);
});

#20 odt on Oct 23rd, 2008

Hello Cory,
I try to use this plugin inside jquery.FileTree plugin to get menu to manipulate folders and files.
Generally it works, but menu shows up few centimeters from place of right-click.
I've added in jqueryFileTree.js folowing line :
$(t).find('LI A').contextMenu({
menu: 'myMenu'
}, function(action, el, pos) { alert('ok'); } );
under lines:
// Prevent A from triggering the # on non-click events
if( o.folderEvent.toLowerCase != 'click' ) $(t).find('LI A').bind('click', function() { return false; });
I've test it in firefox 3.0.3
Any ideas?

#21 Lukasz on Oct 28th, 2008

@Lukasz: probably CSS. Do you have a link you could send?

#22 Cory S.N. LaViska on Oct 28th, 2008

Hello Cory,
Thank you for your interest. It was CSS issue.
I had to div's like this:
<div id="container"><div id="file_list"></div></div>.
When I remove "position: relative" from #container style definition submenu shows up in right place.

Thanks

#23 Lukasz on Oct 29th, 2008

Hi! Great menu!
Add please 'mouseButton' option, to allow user to set left button for menu opening instead of right button.

Thanks!

#24 Yaroslav on Oct 29th, 2008

It goes without saying, but this stuff is awesome. I hadn't seen an example of how to integrate this with your grid. Do you have any examples?
Also, I modified the grid (crudely) to make it work with WCF json services. If you would like, I can send them to you, it works great.
Again, thanks.

#25 Heath on Oct 29th, 2008

I have the same issue as Paul in Safari 3.1.2 on Leopard 10.5.5.
Exactly i have to click first with the right button and then the left button to see the context menu.
(no issues with http://www.trendskitchens.co.nz/jquery/contextmenu/)

#26 Frank on Nov 1st, 2008

Cory, are the icons provided in the zip are distrubuted under the Creative Commons License too and did you yourself created them?
Regards from Germany,
Frank

#27 Frank on Nov 1st, 2008

@Frank: I'm going to rework the way the context menu is binded to events which will hopefully solve that problem. It must be platform specific, as it doesn't happen in Safari 3.1.2 on Windows.

The icons are from the Silk Icons set: http://www.famfamfam.com/lab/icons/silk/

They are licensed under the Creative Commons Attribution 2.5 license.

#28 Cory S.N. LaViska on Nov 1st, 2008

Right now the only callback is made on a click of a menu option. It would be nice to have another optional callback that could be made on the initial click so that menu options could be disabled or enabled based on the precise element clicked.

#29 Greg on Nov 4th, 2008

I like how this is simple and uses pure CSS, one thing i changed for my purposes was I passed the evt, variable into my callback function.

So in the event you have child elements with children you can find exactly which element was selected via (e.target || e.srcElement).innerHTML where "e" is the new parameter. And i can just bind use the parent element in my selector.

#30 Matt on Nov 10th, 2008

I needed a function to modify the contents of the menu depending on what I clicked on, so using I added a third parameter (a function) and send the source element to it.

This solution might help comment #29.

line 20 changed to:
contextMenu: function(o, callback, callfront) {

line 40 added:
if (callfront) callfront( $(srcElement) );

#31 Jeff on Nov 11th, 2008

How could we make the contextmenu appear onhover and not by clicking.

#32 andrewb on Nov 19th, 2008

@andrewb: You'd have to modify the current version of the plugin to do this. Look for this ability in the next release :)

#33 Cory S.N. LaViska on Nov 20th, 2008

a couple of things:
- make this plugin dependent on your Right-click Plugin - this would allow rightclick event delegation, not just for this plugin either.
- remove internal hover event binding, they can be done with CSS...maybe not in ie6 tho, but you can always restyle the menu and css :hover on the anchor tags if needed.

thanks,
Leon

#34 Leon Sorokin on Nov 21st, 2008

very nice plugin but it is considered good practise to try and take up only one namespace in jQuery.fn

#35 adam j. sontag on Nov 24th, 2008

in Line 68: (e.pageY) ? y = e.pageY : x = e.clientY + d.scrollTop;

seems to be a typo: x = e.clientY has to be y = e.clientY

Or am I wrong?

#36 uprocka on Nov 26th, 2008

I'm a complete CSS newbie. How do you make the context menu display with a drop shadow?

#37 anonymous on Dec 5th, 2008

The demo seems not to work on Safari 3.2.1 (Leopard)

#38 Marco on Dec 11th, 2008

FYI, I posted my code for adding this to the jQuery File Tree in comment #149 on this page:
http://abeautifulsite.net/notebook.php?article=58#comments

This adds one context menu to folders and a different one to files as each has different actions.

#39 Tyler on Dec 11th, 2008

i'm trying to run a this script but not work ie7 and opera. i'm not tested under Firefox.

#40 Sedat Kumcu on Dec 11th, 2008

I just found another bug. When pressing up the last option will set to hover even if it is disabled.

The line around Line 91
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');

should be
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:not(.disabled):last').addClass('hover');

#41 Kikuchyo on Dec 13th, 2008

Thank you SOOOOOO.... much for this script. It was 99.9% of what I wanted. I also wanted the ability to disable RIGHT mouse click on the body without disrupting RIGHT mouse click on the elements which I attached your right click menu.

The solution was to place:

$(document).bind("contextmenu",function(e){return false;});

right befor your javascript code. This prevents anyone from RIGHT mouseing and stealing source code, but the menus still work....

Thanks again!
Neal

#42 Neal on Dec 19th, 2008

Any idea when support for nested menus would be added?

Thank you very much.

#43 Robin on Dec 19th, 2008

Couple more small issues when inside a "overflow:auto" DIV. Need to sense how close to the right hand side of the div and how close to the bottom of the div and perhaps show the context menu where it will be in full view.

Off right side example: http://qwebmedia.com/jing/neal/2008-12-20_0753.png

Off bottom example: http://qwebmedia.com/jing/neal/2008-12-20_0754.png

#44 Neal Chapman on Dec 20th, 2008

ODT:
==============
my html code is like this:
<ul id="items">
<li id="item1"><a href="#">Item 1</a>
<ul>
<li id="item1-1"><a href="#">Item 1.1</a></li>
</ul>
</li>
</ul>

==============

The issue is event bubble, as you have right clicked, there are two events generated--one from the children and the other from the parent.
However since the event order is:
children--->parent
the event will then bubble down to the parent, thus the children menu will be hidden and ignored.
To solve it:
in
$(this).mouseup( function(e) {
var srcElement = $j(this);
..................
return false; //add this! to prevent event bubble
}

#45 HYL on Dec 31st, 2008

Add a comment

Name*

Email*

Never, ever sold or spammed :)

Homepage

Comment*

Sorry, plain text only :(