How to add a custom right-click menu to a webpage?
Asked Answered
S

23

424

I want to add a custom right-click menu to my web application. Can this be done without using any pre-built libraries? If so, how to display a simple custom right-click menu which does not use a 3rd party JavaScript library?

I'm aiming for something like what Google Docs does. It lets users right-click and show the users their own menu.

NOTE: I want to learn how to make my own versus using something somebody made already since most of the time, those 3rd party libraries are bloated with features whereas I only want features that I need so I want it to be completely hand-made by me.

Segalman answered 5/2, 2011 at 19:32 Comment(5)
just stumbled upon: davidwalsh.name/html5-context-menu love HTML5Stinko
This is definitely not a duplicate. As the question require answers without 3rd party libraries, and the other one is likely to use Jquery (I wanted to write a context Google’s drive like context menu inside a userscript).Kantor
just today I found two more good examples (I think) about this: DEMO 1 // DEMO 2 (this demo need jquery UI) I hope help to anybody, bb.Allowed
Just want to point out that the HTML5 context menu is only supported in some versions of Firefox and as far as I can tell nothing else supports it. Chrome as of Version 61 does not support it.Aggri
For people using React - native-menu replicates all of the existing functionality (copy, open in new tab, search on google etc.) whilst looking native (applies different styles depending on the browser). demoRaff
H
325

Answering your question - use contextmenu event, like below:

if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    alert("You've tried to open context menu"); //here you draw your own menu
    e.preventDefault();
  }, false);
} else {
  document.attachEvent('oncontextmenu', function() {
    alert("You've tried to open context menu");
    window.event.returnValue = false;
  });
}
<body>
  Lorem ipsum...
</body>

But you should ask yourself, do you really want to overwrite default right-click behavior - it depends on application that you're developing.


JSFIDDLE

Hirsutism answered 5/2, 2011 at 19:59 Comment(11)
Is it cross-browser compatible?Segalman
Tested on Opera 11.01, Firefox 3.6.13, Chrome 9, Safari 5 (all 4 via addEventListener) and IE 8 (attachEvent).Hirsutism
You have just explained how to disable the right-click menu. How to create our own menu??Mullock
@Mullock You know place, where user has clicked, and you don't have original menu. Create a container in that place and display your menu there.Hirsutism
You don't need preventDefault. Opening an alert() box will close the context menu automatically.Greenland
Does anyone know is it possible to default this? For instance, a web app has this implemented, but I want to be able to click an element and for instance; open the developer tools on that instance. As an example, by holding down alt, and right clicking - the context menu will always be the standard one implemented by the browser? Perhaps Chrome and other browsers should have this implemented?Ritzy
@Ritzy When you look into code, you will see this line e.preventDefault();. This is why regular menu isn't shown. What you can do is to create some conditional logic which checks, if key is pressed while right clicking and then NOT calling e.preventDefault() - you will get regular browser menu then.Hirsutism
Ah I understand that is possible @singles, I was just wondering if anyone knew of any browser defaults for that. I guess not. Thanks though; you're right, that'd work!Ritzy
"But you should ask yourself, do you really want to overwrite default right-click behavior" -- There is an important difference between this solution and the implementation in the answer below by @MohamedIqzas (https://mcmap.net/q/80890/-how-to-add-a-custom-right-click-menu-to-a-webpage). In the answer below the default context menu is suppressed only for a certain HTML element, not for the whole document. This makes it much less intrusive.Phillada
@TylerLong That's not quite correct. The answer demonstrates the basics of how to add a custom menu although it misses to actually create a custom menu. You need to replace the line with the comment //here you draw your own menu with code to create a custom menu using "normal" HTML markup.Bruner
According to MDN, this won't work on iOS safari. The bug it links to mentions VoiceOver in its title. TBH, I'm not sure what that means; on iOS is this completely broken or conditionally broken?Mopup
A
93

Was very useful for me. For the sake of people like me, expecting the drawing of menu, I put here the code I used to make the right-click menu:

$(document).ready(function() {


  if ($("#test").addEventListener) {
    $("#test").addEventListener('contextmenu', function(e) {
      alert("You've tried to open context menu"); //here you draw your own menu
      e.preventDefault();
    }, false);
  } else {

    //document.getElementById("test").attachEvent('oncontextmenu', function() {
    //$(".test").bind('contextmenu', function() {
    $('body').on('contextmenu', 'a.test', function() {


      //alert("contextmenu"+event);
      document.getElementById("rmenu").className = "show";
      document.getElementById("rmenu").style.top = mouseY(event) + 'px';
      document.getElementById("rmenu").style.left = mouseX(event) + 'px';

      window.event.returnValue = false;


    });
  }

});

// this is from another SO post...  
$(document).bind("click", function(event) {
  document.getElementById("rmenu").className = "hide";
});



function mouseX(evt) {
  if (evt.pageX) {
    return evt.pageX;
  } else if (evt.clientX) {
    return evt.clientX + (document.documentElement.scrollLeft ?
      document.documentElement.scrollLeft :
      document.body.scrollLeft);
  } else {
    return null;
  }
}

function mouseY(evt) {
  if (evt.pageY) {
    return evt.pageY;
  } else if (evt.clientY) {
    return evt.clientY + (document.documentElement.scrollTop ?
      document.documentElement.scrollTop :
      document.body.scrollTop);
  } else {
    return null;
  }
}
.show {
  z-index: 1000;
  position: absolute;
  background-color: #C0C0C0;
  border: 1px solid blue;
  padding: 2px;
  display: block;
  margin: 0;
  list-style-type: none;
  list-style: none;
}

.hide {
  display: none;
}

.show li {
  list-style: none;
}

.show a {
  border: 0 !important;
  text-decoration: none;
}

.show a:hover {
  text-decoration: underline !important;
}
<!-- jQuery should be at least version 1.7 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="contextmenu.js"></script>
<link rel="stylesheet" href="contextmenu.css" />


<div id="test1">
  <a href="www.google.com" class="test">Google</a>
  <a href="www.google.com" class="test">Link 2</a>
  <a href="www.google.com" class="test">Link 3</a>
  <a href="www.google.com" class="test">Link 4</a>
</div>

<!-- initially hidden right-click menu -->
<div class="hide" id="rmenu">
  <ul>
    <li>
      <a href="http://www.google.com">Google</a>
    </li>

    <li>
      <a href="http://localhost:8080/login">Localhost</a>
    </li>

    <li>
      <a href="C:\">C</a>
    </li>
  </ul>
</div>
Anthropomorphosis answered 10/5, 2013 at 11:18 Comment(5)
@Schism Suffixed mouseY(event) and mouseX(event) with px to make it work as expected: http://jsfiddle.net/a6w7n64o/.Zygote
@Adelphia - Anything not native and not created by yourself is third party. jQuery really isn't all that bloated with extra stuff. Not to the degree that it would slow anything down. It's very useful and the same jQuery used in this answer could easily be converted to standard JavaScript commands. It may not be 100% inline with the request in the original question, but it's definitely 95% inline with it.Gasperoni
@TheDukeOfMarshallשלם I wasn't asking anyone to write the code for me, just to explain how to do it. The selected answer did that perfectly.Forrest
In firefox 39 the default contextmenu still shows up over the top of the custom menu. Also the custom menu dismisses instantly after displaying.Darceydarci
@Darceydarci I had the same problem with Firefox 58. This post describes a solution, which works for me: https://mcmap.net/q/82123/-disable-firefox-39-s-silly-right-click-context-menu You disable event-propagation for document and register your context-menu-handler on the window object. Here is an adjusted fiddle: jsfiddle.net/jjgkLe3g/1Ratable
H
52

A combination of some nice CSS and some non-standard html tags with no external libraries can give a nice result (JSFiddle)

HTML

<menu id="ctxMenu">
    <menu title="File">
        <menu title="Save"></menu>
        <menu title="Save As"></menu>
        <menu title="Open"></menu>
    </menu>
    <menu title="Edit">
        <menu title="Cut"></menu>
        <menu title="Copy"></menu>
        <menu title="Paste"></menu>
    </menu>
</menu>

Note: the menu tag does not exist, I'm making it up (you can use anything)

CSS

#ctxMenu{
    display:none;
    z-index:100;
}
menu {
    position:absolute;
    display:block;
    left:0px;
    top:0px;
    height:20px;
    width:20px;
    padding:0;
    margin:0;
    border:1px solid;
    background-color:white;
    font-weight:normal;
    white-space:nowrap;
}
menu:hover{
    background-color:#eef;
    font-weight:bold;
}
menu:hover > menu{
    display:block;
}
menu > menu{
    display:none;
    position:relative;
    top:-20px;
    left:100%;
    width:55px;
}
menu[title]:before{
    content:attr(title);
}
menu:not([title]):before{
    content:"\2630";
}

The JavaScript is just for this example, I personally remove it for persistent menus on windows

var notepad = document.getElementById("notepad");
notepad.addEventListener("contextmenu",function(event){
    event.preventDefault();
    var ctxMenu = document.getElementById("ctxMenu");
    ctxMenu.style.display = "block";
    ctxMenu.style.left = (event.pageX - 10)+"px";
    ctxMenu.style.top = (event.pageY - 10)+"px";
},false);
notepad.addEventListener("click",function(event){
    var ctxMenu = document.getElementById("ctxMenu");
    ctxMenu.style.display = "";
    ctxMenu.style.left = "";
    ctxMenu.style.top = "";
},false);

Also note, you can potentially modify menu > menu{left:100%;} to menu > menu{right:100%;} for a menu that expands from right to left. You would need to add a margin or something somewhere though

Haemolysis answered 24/5, 2015 at 1:43 Comment(3)
You might want to add return false; at the end of the function that handles the "contextmenu" event to support more browsers(-versions).Considering
If my intention is for the menu items to show a popup going to a URL, would wrapping the menu item HTML tags in <a> tags be the way to go for that, would it be more common to write JS code that makes the popup happen on click? Great example. This is exactly what I was looking for: a context menu built from the basic building blocks. I think this is very useful even if I end up using a library because of the understanding I am getting from it.Reviviscence
@PhilippeCarphin you can use what ever tags you want. Anchor tags probably make better sense. Also, the menu[title]:before is the magic that injects the title into the tag, so you dont have to use this and can fill out the content in the tags as you see fitHaemolysis
E
42

According to the answers here and on other 'flows, I've made a version that looks like the one of Google Chrome, with css3 transition. JS Fiddle

Lets start easy, since we have the js above on this page, we can worry about the css and layout. The layout that we will be using is an <a> element with a <img> element or a font awesome icon (<i class="fa fa-flag"></i>) and a <span> to show the keyboard shortcuts. So this is the structure:

<a href="#" onclick="doSomething()">
  <img src="path/to/image.gif" />
  This is a menu option
  <span>Ctrl + K</span>
</a>

We will put these in a div and show that div on the right-click. Let's style them like in Google Chrome, shall we?

#menu a {
  display: block;
  color: #555;
  text-decoration: no[...]

Now we will add the code from the accepted answer, and get the X and Y value of the cursor. To do this, we will use e.clientX and e.clientY. We are using client, so the menu div has to be fixed.

var i = document.getElementById("menu").style;
if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.client[...]

And that is it! Just add the css transisions to fade in and out, and done!

var i = document.getElementById("menu").style;
if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.clientY;
    menu(posX, posY);
    e.preventDefault();
  }, false);
  document.addEventListener('click', function(e) {
    i.opacity = "0";
    setTimeout(function() {
      i.visibility = "hidden";
    }, 501);
  }, false);
} else {
  document.attachEvent('oncontextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.clientY;
    menu(posX, posY);
    e.preventDefault();
  });
  document.attachEvent('onclick', function(e) {
    i.opacity = "0";
    setTimeout(function() {
      i.visibility = "hidden";
    }, 501);
  });
}

function menu(x, y) {
  i.top = y + "px";
  i.left = x + "px";
  i.visibility = "visible";
  i.opacity = "1";
}
body {
  background: white;
  font-family: sans-serif;
  color: #5e5e5e;
}

#menu {
  visibility: hidden;
  opacity: 0;
  position: fixed;
  background: #fff;
  color: #555;
  font-family: sans-serif;
  font-size: 11px;
  -webkit-transition: opacity .5s ease-in-out;
  -moz-transition: opacity .5s ease-in-out;
  -ms-transition: opacity .5s ease-in-out;
  -o-transition: opacity .5s ease-in-out;
  transition: opacity .5s ease-in-out;
  -webkit-box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  -moz-box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  padding: 0px;
  border: 1px solid #C6C6C6;
}

#menu a {
  display: block;
  color: #555;
  text-decoration: none;
  padding: 6px 8px 6px 30px;
  width: 250px;
  position: relative;
}

#menu a img,
#menu a i.fa {
  height: 20px;
  font-size: 17px;
  width: 20px;
  position: absolute;
  left: 5px;
  top: 2px;
}

#menu a span {
  color: #BCB1B3;
  float: right;
}

#menu a:hover {
  color: #fff;
  background: #3879D9;
}

#menu hr {
  border: 1px solid #EBEBEB;
  border-bottom: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet"/>
<h2>CSS3 and JAVASCRIPT custom menu.</h2>
<em>Stephan Stanisic | Lisence free</em>
<p>Right-click anywhere on this page to open the custom menu. Styled like the Google Chrome contextmenu. And yes, you can use <i class="fa fa-flag"></i>font-awesome</p>
<p style="font-size: small">
  <b>Lisence</b>
  <br /> "THE PIZZA-WARE LICENSE" (Revision 42):
  <br /> You can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a Pizza in return.
  <br />
  <a style="font-size:xx-small" href="https://github.com/KLVN/UrbanDictionary_API#license">https://github.com/KLVN/UrbanDictionary_API#license</a>
</p>
<br />
<br />
<small>(The white body background is just because I hate the light blue editor background on the result on jsfiddle)</small>
<div id="menu">
  <a href="#">
    <img src="http://puu.sh/nr60s/42df867bf3.png" /> AdBlock Plus <span>Ctrl + ?!</span>
  </a>
  <a href="#">
    <img src="http://puu.sh/nr5Z6/4360098fc1.png" /> SNTX <span>Ctrl + ?!</span>
  </a>
  <hr />
  <a href="#">
    <i class="fa fa-fort-awesome"></i> Fort Awesome <span>Ctrl + ?!</span>
  </a>
  <a href="#">
    <i class="fa fa-flag"></i> Font Awesome <span>Ctrl + ?!</span>
  </a>
</div>
Erythrocytometer answered 1/3, 2016 at 18:20 Comment(4)
This saved me a huge head ache! If OP was looking for a simple way to use on whole webpage and not just a div, this should be accepted answer:)Glyceride
When you right-click the right part of the page, some part of the menu hides.Shakta
@Stephan Stanisic Can you guide me how to add submenu into this? I love this snippet it's just outstanding and working great for me. ThanksCareless
I used this example in order to form a context menu from uranus.codingneko.repl.coSinglecross
M
30

Simplest jump start function, create a context menu at the cursor position, that destroys itself on mouse leave.

oncontextmenu = (e) => {
  e.preventDefault()
  let menu = document.createElement("div")
  menu.id = "ctxmenu"
  menu.style = `top:${e.pageY-10}px;left:${e.pageX-40}px`
  menu.onmouseleave = () => ctxmenu.outerHTML = ''
  menu.innerHTML = "<p>Option1</p><p>Option2</p><p>Option3</p><p>Option4</p><p onclick='alert(`Thank you!`)'>Upvote</p>"
  document.body.appendChild(menu)
}
#ctxmenu {
  position: fixed;
  background: ghostwhite;
  color: black;
  cursor: pointer;
  border: 1px black solid
}

#ctxmenu > p {
  padding: 0 1rem;
  margin: 0
}

#ctxmenu > p:hover {
  background: black;
  color: ghostwhite
}
Millibar answered 4/10, 2020 at 2:27 Comment(5)
This is a nice solution but if you double click it will be a problem!Mira
Yes it's very simple. To avoid the problem you underline, we might have to test if the element with the id ctxmenu yet exist in the DOM. On the same logic, instead of parsing, we should use a variable with a boolean, like isDisplayed = true/falseMillibar
In this case, the correct code should be like this ;) oncontextmenu = (e) => { const ctxmenudiv = document.getElementById('ctxmenu'); if (ctxmenudiv === null) { e.preventDefault(); const menu = document.createElement("div"); menu.id = "ctxmenu" menu.style = top:${e.pageY-10}px;left:${e.pageX-40}px menu.onmouseleave = () => ctxmenu.outerHTML = '' menu.innerHTML = "<p>Option1</p><p>Option2</p><p>Option3</p><p>Option4</p><p onclick='alert(Thank you!)'>Upvote</p>" document.body.appendChild(menu); } }Mira
less is more, best answerOverstudy
Nice and simple, solves the problem, non-obnoxious styling. Thank you!Nadia
C
15

Pure JS and css solution for a truly dynamic right click context menu, albeit based on predefined naming conventions for the elements id, links etc. jsfiddle and the code you could copy paste into a single static html page :

var rgtClickContextMenu = document.getElementById('div-context-menu');

/** close the right click context menu on click anywhere else in the page*/
document.onclick = function(e) {
  rgtClickContextMenu.style.display = 'none';
}

/**
 present the right click context menu ONLY for the elements having the right class
 by replacing the 0 or any digit after the "to-" string with the element id , which
 triggered the event
*/
document.oncontextmenu = function(e) {
  //alert(e.target.id)
  var elmnt = e.target
  if (elmnt.className.startsWith("cls-context-menu")) {
    e.preventDefault();
    var eid = elmnt.id.replace(/link-/, "")
    rgtClickContextMenu.style.left = e.pageX + 'px'
    rgtClickContextMenu.style.top = e.pageY + 'px'
    rgtClickContextMenu.style.display = 'block'
    var toRepl = "to=" + eid.toString()
    rgtClickContextMenu.innerHTML = rgtClickContextMenu.innerHTML.replace(/to=\d+/g, toRepl)
    //alert(rgtClickContextMenu.innerHTML.toString())
  }
}
.cls-context-menu-link {
  display: block;
  padding: 20px;
  background: #ECECEC;
}

.cls-context-menu {
  position: absolute;
  display: none;
}

.cls-context-menu ul,
#context-menu li {
  list-style: none;
  margin: 0;
  padding: 0;
  background: white;
}

.cls-context-menu {
  border: solid 1px #CCC;
}

.cls-context-menu li {
  border-bottom: solid 1px #CCC;
}

.cls-context-menu li:last-child {
  border: none;
}

.cls-context-menu li a {
  display: block;
  padding: 5px 10px;
  text-decoration: none;
  color: blue;
}

.cls-context-menu li a:hover {
  background: blue;
  color: #FFF;
}
<!-- those are the links which should present the dynamic context menu -->
<a id="link-1" href="#" class="cls-context-menu-link">right click link-01</a>
<a id="link-2" href="#" class="cls-context-menu-link">right click link-02</a>

<!-- this is the context menu -->
<!-- note the string to=0 where the 0 is the digit to be replaced -->
<div id="div-context-menu" class="cls-context-menu">
  <ul>
    <li><a href="#to=0">link-to=0 -item-1 </a></li>
    <li><a href="#to=0">link-to=0 -item-2 </a></li>
    <li><a href="#to=0">link-to=0 -item-3 </a></li>
  </ul>
</div>
Confucius answered 30/1, 2019 at 18:5 Comment(2)
This is more the answer I was expecting, an example actually modifying the right click menuDiedrediefenbaker
yup , a similar example could be: codepen.io/yordangeorgiev/pen/GzWJzd and the final product : qto.fi/qto/view/concepts_doc ( just click on the login ... )Confucius
A
14

You could try simply blocking the context menu by adding the following to your body tag:

<body oncontextmenu="return false;">

This will block all access to the context menu (not just from the right mouse button but from the keyboard as well).

P.S. you can add this to any tag you want to disable the context menu on

for example:

<div class="mydiv" oncontextmenu="return false;">

Will disable the context menu in that particular div only

Ardath answered 7/6, 2013 at 15:27 Comment(0)
G
13
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<head>

<title>Context menu - LabLogic.net</title>

</head>
<body>

<script language="javascript" type="text/javascript">

document.oncontextmenu=RightMouseDown;
document.onmousedown = mouseDown; 



function mouseDown(e) {
    if (e.which===3) {//righClick
        alert("Right-click menu goes here");
    }
}


function RightMouseDown() { return false; }

</script>

</body>
</html>

Tested and works in Opera 11.6, firefox 9.01, Internet Explorer 9 and chrome 17

Galarza answered 6/3, 2012 at 2:23 Comment(2)
It works, but the demo menu on your page is really tiny and cramped. Good example, though.Acceleration
It works if you're using a three-button mouse. Ctrl-click leaves the user high and dry. @Singles has a better suggestion, even if it does leave a bit to the imagination.Reexamine
O
9

Try this:

var cls = true;
var ops;

window.onload = function() {
    document.querySelector(".container").addEventListener("mouseenter", function() {
        cls = false;
    });
    document.querySelector(".container").addEventListener("mouseleave", function() {
        cls = true;
    });
    ops = document.querySelectorAll(".container td");
    for (let i = 0; i < ops.length; i++) {
        ops[i].addEventListener("click", function() {
            document.querySelector(".position").style.display = "none";
        });
    }

    ops[0].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 1!");
        }, 50);
    });

    ops[1].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 2!");
        }, 50);
    });

    ops[2].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 3!");
        }, 50);
    });

    ops[3].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 4!");
        }, 50);
    });

    ops[4].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 5!");
        }, 50);
    });
}

document.addEventListener("contextmenu", function() {
    var e = window.event;
    e.preventDefault();
    document.querySelector(".container").style.padding = "0px";

    var x = e.clientX;
    var y = e.clientY;

    var docX = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || document.body.offsetWidth;
    var docY = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || document.body.offsetHeight;

    var border = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('border-width'));

    var objX = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('width')) + 2;
    var objY = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('height')) + 2;

    if (x + objX > docX) {
        let diff = (x + objX) - docX;
        x -= diff + border;
    }

    if (y + objY > docY) {
        let diff = (y + objY) - docY;
        y -= diff + border;
    }

    document.querySelector(".position").style.display = "block";

    document.querySelector(".position").style.top = y + "px";
    document.querySelector(".position").style.left = x + "px";
});

window.addEventListener("resize", function() {
    document.querySelector(".position").style.display = "none";
});

document.addEventListener("click", function() {
    if (cls) {
        document.querySelector(".position").style.display = "none";
    }
});

document.addEventListener("wheel", function() {
    if (cls) {
        document.querySelector(".position").style.display = "none";
        static = false;
    }
});
.position {
    position: absolute;
    width: 1px;
    height: 1px;
    z-index: 2;
    display: none;
}

.container {
    width: 220px;
    height: auto;
    border: 1px solid black;
    background: rgb(245, 243, 243);
}

.container p {
    height: 30px;
    font-size: 18px;
    font-family: arial;
    width: 99%;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    background: rgb(245, 243, 243);
    color: black;
    transition: 0.2s;
}

.container p:hover {
    background: lightblue;
}

td {
    font-family: arial;
    font-size: 20px;
}

td:hover {
    background: lightblue;
    transition: 0.2s;
    cursor: pointer;
}
<div class="position">
    <div class="container" align="center">
        <table style="text-align: left; width: 99%; margin-left: auto; margin-right: auto;" border="0" cellpadding="2" cellspacing="2">
            <tbody>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 1<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 2<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 3<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 4<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 5<br>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
Orgy answered 24/2, 2021 at 17:48 Comment(1)
I'd say this is the best answer because it shows an actuall snippet where you can see action occuring when you pick different options. +1!Leptorrhine
S
7

Here is a very good tutorial on how to build a custom context menu with a full working code example (without JQuery and other libraries).

You can also find their demo code on GitHub.

They give a detailed step-by-step explanation that you can follow along to build your own right-click context menu (including html, css and javascript code) and summarize it at the end by giving the complete example code.

You can follow along easily and adapt it to your own needs. And there is no need for JQuery or other libraries.

This is how their example menu code looks like:

<nav id="context-menu" class="context-menu">
    <ul class="context-menu__items">
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="View"><i class="fa fa-eye"></i> View Task</a>
      </li>
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="Edit"><i class="fa fa-edit"></i> Edit Task</a>
      </li>
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="Delete"><i class="fa fa-times"></i> Delete Task</a>
      </li>
    </ul>
  </nav>

A working example (task list) can be found on codepen.

Shithead answered 4/10, 2016 at 6:56 Comment(2)
A short summary would help reviewers (like me) to judge the validity of your answer, and may save some readers from following that link. Just a sentence or two would be fine and not too much work.Radiochemistry
@IngoKarkat Thanks for your advice. I added some explanation. Hope you find this helpful. It helped me a lot.Shithead
I
7

I know this has already been answered, but I spent some time wrestling with the second answer to get the native context menu to disappear and have it show up where the user clicked.
HTML

<body>
    <div id="test1">
        <a href="www.google.com" class="test">Google</a>
        <a href="www.google.com" class="test">Link 2</a>
        <a href="www.google.com" class="test">Link 3</a>
        <a href="www.google.com" class="test">Link 4</a>
    </div>

    <!-- initially hidden right-click menu -->
    <div class="hide" id="rmenu">
        <ul>
            <li class="White">White</li>
            <li>Green</li>
            <li>Yellow</li>
            <li>Orange</li>
            <li>Red</li>
            <li>Blue</li>
        </ul>
    </div>
</body>

CSS

.hide {
  display: none;
}

#rmenu {
  border: 1px solid black;
  background-color: white;
}

#rmenu ul {
  padding: 0;
  list-style: none;
}
#rmenu li
{
  list-style: none;
  padding-left: 5px;
  padding-right: 5px;
}

JavaScript

if (document.getElementById('test1').addEventListener) {
    document.getElementById('test1').addEventListener('contextmenu', function(e) {
            $("#rmenu").toggleClass("hide");
            $("#rmenu").css(
              {
                position: "absolute",
                top: e.pageY,
                left: e.pageX
              }
            );
            e.preventDefault();
     }, false);
}

// this is from another SO post...  
$(document).bind("click", function(event) {
  document.getElementById("rmenu").className = "hide";
});

CodePen Example

Indue answered 10/11, 2016 at 19:32 Comment(0)
M
6

Try This

$(function() {
var doubleClicked = false;
$(document).on("contextmenu", function (e) {
if(doubleClicked == false) {
e.preventDefault(); // To prevent the default context menu.
var windowHeight = $(window).height()/2;
var windowWidth = $(window).width()/2;
if(e.clientY > windowHeight && e.clientX <= windowWidth) {
  $("#contextMenuContainer").css("left", e.clientX);
  $("#contextMenuContainer").css("bottom", $(window).height()-e.clientY);
  $("#contextMenuContainer").css("right", "auto");
  $("#contextMenuContainer").css("top", "auto");
} else if(e.clientY > windowHeight && e.clientX > windowWidth) {
  $("#contextMenuContainer").css("right", $(window).width()-e.clientX);
  $("#contextMenuContainer").css("bottom", $(window).height()-e.clientY);
  $("#contextMenuContainer").css("left", "auto");
  $("#contextMenuContainer").css("top", "auto");
} else if(e.clientY <= windowHeight && e.clientX <= windowWidth) {
  $("#contextMenuContainer").css("left", e.clientX);
  $("#contextMenuContainer").css("top", e.clientY);
  $("#contextMenuContainer").css("right", "auto");
  $("#contextMenuContainer").css("bottom", "auto");
} else {
  $("#contextMenuContainer").css("right", $(window).width()-e.clientX);
  $("#contextMenuContainer").css("top", e.clientY);
  $("#contextMenuContainer").css("left", "auto");
  $("#contextMenuContainer").css("bottom", "auto");
}
 $("#contextMenuContainer").fadeIn(500, FocusContextOut());
  doubleClicked = true;
} else {
  e.preventDefault();
  doubleClicked = false;
  $("#contextMenuContainer").fadeOut(500);
}
});
function FocusContextOut() {
 $(document).on("click", function () {
   doubleClicked = false; 
   $("#contextMenuContainer").fadeOut(500);
   $(document).off("click");           
 });
}
});

http://jsfiddle.net/AkshayBandivadekar/zakn7Lwb/14/

Marivelmariya answered 11/7, 2015 at 9:56 Comment(5)
Code is great, but please include some description about what the OPs problem actually is, and how this solves it.Loquacity
I like this solution, however in firefox 39 the menu dismisses on its own right after it comes up.Darceydarci
This solution doesn't actually work if you force the page to have a scroll (say you add a bunch of <br> tags) and are somewhere in the bottom part of it.Regine
You should be using clientX and clientY instead of pageX and pageY for this to work; check out this great answer: #9263241Regine
Yes, DanielM there is issue with right click menu while scrolling so this overcome by using clientX and clientY instead of pageX and pageY, I made changes to code. Thanks for help ...Marivelmariya
L
3

You can do it with this code. visit here for full tutorial with automatic edge detection http://www.voidtricks.com/custom-right-click-context-menu/

$(document).ready(function () {
 $("html").on("contextmenu",function(e){
        //prevent default context menu for right click
        e.preventDefault();

        var menu = $(".menu"); 

        //hide menu if already shown
        menu.hide(); 

        //get x and y values of the click event
        var pageX = e.pageX;
        var pageY = e.pageY;

        //position menu div near mouse cliked area
        menu.css({top: pageY , left: pageX});

        var mwidth = menu.width();
        var mheight = menu.height();
        var screenWidth = $(window).width();
        var screenHeight = $(window).height();

        //if window is scrolled
        var scrTop = $(window).scrollTop();

        //if the menu is close to right edge of the window
        if(pageX+mwidth > screenWidth){
        menu.css({left:pageX-mwidth});
        }

        //if the menu is close to bottom edge of the window
        if(pageY+mheight > screenHeight+scrTop){
        menu.css({top:pageY-mheight});
        }

        //finally show the menu
        menu.show();
 }); 

 $("html").on("click", function(){
 $(".menu").hide();
 });
 });

`

Linseylinseywoolsey answered 20/10, 2015 at 15:44 Comment(0)
C
2

December 2023 update:

Here is an example of my Menu class which I use to implement context menu on notes in a note management application.

Features:

  • True OOP with encapsulation and clearly defined API (currently just one single public method).
  • No third-party dependencies. Just plain HTML, CSS and JavaScript.
  • Does not interfere with the default browser context menu.
  • Closes when clicked on another item, clicked outside of the menu, pressing ESC key or scrolling the main window.
  • Two callbacks onOpen and onClose.
  • The menu itself requires no HTML.

'use strict';

class Menu {
    #onOpen;
    #onClose;
    #container;
    #containerCssClassName = 'menu';

    constructor({ target, onOpen, onClose }) {
        this.#onOpen = onOpen;
        this.#onClose = onClose;
        this.#createContainer();

        document.addEventListener('click', this.#hide.bind(this));
        document.addEventListener('contextmenu', this.#hide.bind(this));

        target.addEventListener('contextmenu', (e) => {
            if (!this.#onOpen(e)) {
                return;
            }

            const absTopPositionPx = e.pageY;
            const absLeftPositionPx = e.pageX;

            this.#show(absTopPositionPx, absLeftPositionPx);
            e.preventDefault();

            document.addEventListener('scroll', this.#hide.bind(this), { once: true });

            // Without this the menu will be immediately closed by the "contextmenu" event on the document
            e.stopPropagation();
        });

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                this.#hide();
            }
        });
    }
    createItem(label, action) {
        const item = document.createElement('li');
        item.classList.add('item');
        item.textContent = label;
        item.addEventListener('click', action.bind(this));

        this.#container.appendChild(item);
    }
    #show(absTopPositionPx, absLeftPositionPx) {
        this.#container.style.top = `${absTopPositionPx}px`;
        this.#container.style.left = `${absLeftPositionPx}px`;
        this.#container.hidden = false;
    }
    #hide() {
        if (this.#container.hidden) return;

        this.#onClose();
        this.#container.hidden = true;
        document.removeEventListener('scroll', this.#hide.bind(this));
    }
    #createContainer() {
        const container = document.createElement('ul');
        container.classList.add(this.#containerCssClassName);
        container.hidden = true;

        this.#container = container;
        document.body.appendChild(container);
    }
}

// Initialize and configure a new menu
const menu = new Menu({
    target: document.querySelector('.js-items-with-context-menu'),
    onOpen: function (_contextMenuEvent) {
        console.log('onOpen callback');
        return true; // A callback must return true.
    },
    onClose: function () {
        console.log('onClose callback');
    }
});
menu.createItem('Edit', function () {
    console.log('Editing...');
});
menu.createItem('Delete', function () {
    console.log('Deleting...');
});
body {
    font-family: sans-serif;
    margin: 0;
    line-height: 150%;
}

ol,
ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

.items-with-context-menu 
{
    display: flex;
}

.items-with-context-menu .item
{
    background: #aaa;
    width: 10em;
    height: 10em;
}

.menu {
    background: white;
    border: #ccc solid 1px;
    border-radius: .5em;
    box-shadow: .3em .3em .5em gray;
    position: absolute;
    user-select: none;
}

.menu .item {
    cursor: default;
    padding: .5em 1em;
}

.menu .item:hover {
    border-radius: .5em;
    background: #f1f1f1;
}
<div class="items-with-context-menu js-items-with-context-menu">
  <div class="item js-item">An item with a context menu</div>
</div>
Caraviello answered 10/12, 2023 at 12:17 Comment(0)
G
1
<script language="javascript" type="text/javascript">
  document.oncontextmenu = RightMouseDown; 
  document.onmousedown = mouseDown; 

  function mouseDown(e) {
    if (e.which==3) {//righClick
      alert("Right-click menu goes here");
    } 
  }

  function RightMouseDown() { 
    return false; 
  }
</script>
</body> 
</html>
Greatcoat answered 28/10, 2013 at 21:1 Comment(1)
You know theres an oncontextmenu event which gets fired (usually on right click)Cris
J
1

A simple way you could do it is use onContextMenu to return a JavaScript function:

<input type="button" value="Example" onContextMenu="return RightClickFunction();">

<script>
 function RightClickFunction() {
  // Enter your code here;
  return false;
 }
</script>

And by entering return false; you will cancel out the context menu.

if you still want to display the context menu you can just remove the return false; line.

Jacquenette answered 12/2, 2014 at 23:45 Comment(0)
I
1

Tested and works in Opera 12.17, firefox 30, Internet Explorer 9 and chrome 26.0.1410.64

document.oncontextmenu =function( evt ){
        alert("OK?");
        return false;
        }
Incorrupt answered 22/6, 2014 at 10:17 Comment(2)
Wouldn't that jut show an alert when the context menu appears? I don't see how it would customize it.Daloris
Hello @StephenOstermiller! The return false hides the normal context menu - so then we can change the alert to something else, such as displaying a custom one using element.style.display = "block"; or somethingCombustor
S
1
<script>
function fun(){
document.getElementById('menu').style.display="block";
}

</script>
<div id="menu" style="display: none"> menu items</div>

<body oncontextmenu="fun();return false;">

What I'm doing up here

  1. Create your own custom div menu and set the position: absolute and display:none in case.

  2. Add to the page or element to be clicked the oncontextmenu event.

  3. Cancel the default browser action with return false.

  4. User js to invoke your own actions.

Shatter answered 26/7, 2017 at 11:47 Comment(0)
K
1

For those looking for a very simple self-contained implementation of a custom context menu using bootstrap 5 and jQuery 3, here it is...

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
    <title>Custom Context Menu</title>
</head>
<style>
#context-menu {
  position: absolute;
  display: none;
}
</style>
<body>
    <div class="container-fluid p-5">
        <div class="row p-5">
            <div class="col-4">
                <span id="some-element" class="border border-2 border-primary p-5">Some element</span>
            </div>
        </div>
        <div id="context-menu" class="dropdown clearfix">
            <ul class="dropdown-menu" style="display:block;position:static;margin-bottom:5px;">
              <li><a class="dropdown-item" href="#" data-value="copy">Copy</a></li>
              <li><hr class="dropdown-divider"></li>
              <li><a class="dropdown-item" href="#" data-value="select-all">Select All</a></li>
            </ul>
        </div>       
        <script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
        <script>
            $('body').on('contextmenu', '#some-element', function(e) {
                $('#context-menu').css({
                    display: "block",
                    left: e.pageX,
                    top: e.pageY
                });
                return false;
            });
            $('html').click(function() {
                $('#context-menu').hide();
            });
            $("#context-menu li a").click(function(e){
                console.log('in context-menu item, value = ' + $(this).data('value'));
            });
        </script>
    </body>
</html>

Adapted from https://codepen.io/anirugu/pen/xjjxvG

Kee answered 4/9, 2022 at 13:55 Comment(1)
I wonder if bootstrap's popover component could be used?Capeskin
M
0

You should remember if you want to use the Firefox only solution, if you want to add it to the whole document you should add contextmenu="mymenu" to the <html> tag not to the body tag.
You should pay attention to this.

Myrilla answered 10/10, 2014 at 17:45 Comment(0)
R
0
<html>
<head>
<style>
.rightclick {
    /* YOUR CONTEXTMENU'S CSS */
    visibility: hidden;
    background-color: white;
    border: 1px solid grey;
    width: 200px;
    height: 300px;
}
</style>
</head>
<body>
  <div class="rightclick" id="ya">
    <p onclick="alert('choc-a-late')">I like chocolate</p><br><p onclick="awe-so-me">I AM AWESOME</p>
  </div>
  <p>Right click to get sweet results!</p>
</body>
<script>
    document.onclick = noClick;
    document.oncontextmenu = rightClick;
    function rightClick(e) {
        e = e || window.event;
        e.preventDefault();
        document.getElementById("ya").style.visibility = "visible";
        console.log("Context Menu v1.3.0 by IamGuest opened.");
   }
function noClick() {
    document.getElementById("ya").style.visibility = "hidden";
    console.log("Context Menu v1.3.0 by IamGuest closed.");
}
</script>
<!-- Coded by IamGuest. Thank you for using this code! -->
</html>

You can tweak and modify this code to make a better looking, more efficient contextmenu. As for modifying an existing contextmenu, I'm not sure how to do that... Check out this fiddle for an organized point of view. Also, try clicking the items in my contextmenu. They should alert you a few awesome messages. If they don't work, try something more... complex.

Radices answered 3/10, 2016 at 20:58 Comment(0)
M
0

I use something similar to the following jsfiddle

function onright(el, cb) {
    //disable right click
    document.body.oncontextmenu = 'return false';
    el.addEventListener('contextmenu', function (e) { e.preventDefault(); return false });
    el.addEventListener('mousedown', function (e) {
        e = e || window.event;
        if (~~(e.button) === 2) {
            if (e.preventDefault) {
                e.preventDefault();
            } else {
                e.returnValue = false;
            }
            return false;
        }
    });

    // then bind Your cb
    el.addEventListener('mousedown', function (e) {
        e = e || window.event;
        ~~(e.button) === 2 && cb.call(el, e);
    });
}

if You target older IE browsers you should anyway complete it with the ' attachEvent; case

Miniskirt answered 4/7, 2018 at 19:26 Comment(0)
S
0

According to mozilla context menu is deprecated: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contextmenu

Schellens answered 19/9, 2023 at 17:7 Comment(1)
You are right, but this doesn't answer the initial questionJacinto

© 2022 - 2025 — McMap. All rights reserved.