JSFiddle - React, Tailwind, and code Playground
HTML
<ul id="nested">
<li id="folder1" class="CMenu"><span>New Folder1</span></li>
<li id="folder2" class="CMenu"><span>New Folder2</span></li>
<li id="folder3" class="CMenu"><span>New Folder3</span></li>
<li id="folder4" class="CMenu"><span>New Folder4</span></li>
<li id="folder5" class="CMenu"><span>New Folder5</span></li>
<li id="folder6" class="CMenu"><span>New Folder6</span></li>
</ul>
CSS
#contextmenu { border:1px solid #999; padding:0; background:#eee; width:200px; list-style-type:none; display:none; }
#contextmenu .separator { border-top:1px solid #999; }
#contextmenu li { margin:0; padding:0;height:30px }
#contextmenu li a { display:block; padding:5px 10px 5px 35px; width:155px; font-size:12px; text-decoration:none; font-family:tahoma,arial,sans-serif; color:#000; background-position:8px 8px; background-repeat:no-repeat; }
#contextmenu li a:hover { background-color:#ddd; }
#contextmenu li a.disabled { color:#ccc; font-style:italic; }
#contextmenu li a.disabled:hover { background-color:#eee; }
/*#contextmenu li a.edit { background-image:url(tree/folder_tree_edit.png); }
#contextmenu li a.new { background-image:url(tree/folder_tree_add.png); }
#contextmenu li a.copy { background-image:url(copy.png); }
#contextmenu li a.paste { background-image:url(paste.png); }
#contextmenu li a.delete { background-image:url(tree/folder_tree_delete.png); }
#contextmenu li a.quit { background-image:url(quit.png); }*/
/* begin MenuSubItem */
#contextmenu ul{border:1px solid #999;padding:0;visibility: hidden;width:200px; list-style-type:none;z-index: 10;left: 0;top: 0;background:#eee;}
#contextmenu li:hover>ul{visibility: visible;top: 100%;}
#contextmenu li ol, li ul{margin:-29px 0 0 200px;padding:0;}
#contextmenu ul ul a{margin-left: auto;}
/*#contextmenu ul li a.single-upload { background-image:url(tree/single_upload.png); }*/
JavaScript
var ContextMenu = new Class({
//implements
Implements: [Options, Events],
//options
options: {
actions: {},
menu: 'contextmenu',
labels: [],
stopEvent: true,
targets: 'body',
trigger: 'contextmenu',
offsets: {
x: 0,
y: 0
},
onShow: function() {},
onHide: function() {},
onClick: function() {},
fadeSpeed: 200
},
//initialization
initialize: function(options) {
//set options
this.setOptions(options);
//option diffs menu
this.menu = this.parseNodes(this.options.labels, this.options.menu).inject(document.body);
this.targets = $$(this.options.targets);
//fx
this.fx = new Fx.Tween(this.menu, {
property: 'opacity',
duration: this.options.fadeSpeed
});
//hide and begin the listener
this.hide().startListener();
//hide the menu
this.menu.setStyles({
position: 'absolute',
top: '-900000px',
display: 'block'
});
},
//get things started
startListener: function() { /* all elemnts */
this.targets.each(function(el) { /* show the menu */
el.addEvent(this.options.trigger, function(e) {
//enabled?
if (!this.options.disabled) {
//prevent default, if told to
if (this.options.stopEvent) {
e.stop();
}
//record this as the trigger
this.options.element = document.id(el);
//position the menu
this.menu.setStyles({
top: (e.page.y + this.options.offsets.y),
left: (e.page.x + this.options.offsets.x),
position: 'absolute',
'z-index': '2000'
...