How to open anchor context menu with JavaScript?

Viewed 1440

I'm trying to open an anchor context menu using only JavaScript, eg for this HTML:

<html>
  <head></head>
  <body>
    <a href="https://stackoverflow.com" id="anchor-el"> Anchor </a>
  </body>
</html>

I want to open the context menu with the native 'Open in link new tab' and 'Open link in new window' options using just JavaScript.

So far I've tried this, and it seems to successfully dispatch a contextmenu event to the anchor, but the context menu doesn't actually show...

document.getElementById('anchor-el').dispatchEvent(new MouseEvent('contextmenu', { bubbles: true }))
5 Answers

From what I understand of your question, you wish to "replace" the normal click event result with the contextmenu result... But with just the two first items of that context menu.

That makes it a custom menu that you have to define. So here is something...

let contextElements = document.querySelectorAll(".context-anchor")
let myContext = document.querySelector(".context")
let contextItems = document.querySelectorAll(".context-item")
let contextHref

// To add event a listener on each .context-anchor element in order to show a "simulated context menu"
contextElements.forEach(function(ce){
  ce.addEventListener("click", function(e){
    e.preventDefault()
    
    // Get the click coord to open the context menu at the right place
    let clickCoords = {x: e.pageX, y: e.pageY}
    // Get the href of the clicked link
    contextHref = ce.href
    
    // Create a mouse event
    let event = document.createEvent('MouseEvents');
    event.initEvent('mycontextmenu', false, true);
    
    // Be ready to handle it
    this.addEventListener('mycontextmenu', function (e) {
      myContext.style.top = clickCoords.y
      myContext.style.left = clickCoords.x
      myContext.style.display= "block"
    }, false);
    
    // Dispatch it
    this.dispatchEvent(event);
  })
})

// Listener for the options of that "simulated context menu"
contextItems.forEach(function(ci){
  ci.addEventListener("click", function(e){
    if(this.getAttribute("data-destination") === "tab"){
      window.open(contextHref,"_blank")
    }else{
      window.open(contextHref,"custom",`width=${0.99*screen.width},height=${0.94*screen.height}`)
    }
  })
})

// To hide the "simulated context menu" when there is a click anywhere else than on a .context-anchor element
document.addEventListener("click", function(e){
  if(myContext.style.display==="block" && e.target.classList.toString().split(" ").indexOf("context-anchor")<0){
    myContext.style.display= "none"
  }
})
.context{
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  border: 1px solid lightgrey;
  background: white;
  margin: 1em;
  box-shadow: 2px 2px 2px grey;
  min-width: 15em;
}

.context-item{
  font-family: "arial";
  padding: 0.5em 2em;
}

.context-item:hover{
  background: lightgrey;
}
<a href="https://stackoverflow.com" class="context-anchor"> Anchor </a><br>
<br>
<a href="http://hmpg.net/" > Normal anchor </a>

<!-- The simulated context menu -->
<div class="context">
  <div class="context-item" data-destination="tab">Open link in a new tab</div>
  <div class="context-item" data-destination="window">Open link in a new window</div>
</div>

NOTE: window.open is blocked in SO snippets for obvious reasons. Try this CodePen for a working demo.

That definitely is a lot of code to create a weird and uncommon browser behavior. So I would not recommand anyone to use it.

I posted that because it was a bounty challenge .oO(lol!)

document.getElementById("anchor-el").addEventListener("click", function() {
    var link = document.getElementById('anchor-el').getAttribute("href");
    window.open(link,'_blank');
});

I believe it'll help you.

If i understood correctly you have to create a custom contextmenu. So here is an example.

const menu = document.querySelector('[data-id=anchor-el]')
const anchor = document.getElementById('anchor-el');

anchor.addEventListener('contextmenu', e => {
  e.preventDefault();
  menu.style.top = e.pageX;
  menu.style.top = e.pageY;
  menu.style.display = 'block';
});

menu.querySelector('li#newTab').addEventListener('click', (evt) => {
  evt.preventDefault();
  console.log('clicked open in new tab');
  window.open(anchor.href);
});
menu.querySelector('li#newWin').addEventListener('click', (evt) => {
  evt.preventDefault();
  console.log('clicked open in new window');
  window.open(anchor.href, '_blank', 'toolbar=0,location=0,menubar=0');
});

document.body.addEventListener('click', (evt) => {
  evt.preventDefault();
  evt.stopPropagation();
  menu.style.display = 'none';
});
[data-id="anchor-el"] {
  width: 15rem;
  display: flex;
  margin: 0;
  padding: 0;
  align-items: stretch;
  align-content: space-evenly;
  flex-direction: column;
  justify-content: space-evenly;
  box-shadow: 0 0.25rem 0.325rem 0.175rem rgba(0, 0, 0, 0.2);
  position: relative;
  display: none;
}

[data-id="anchor-el"] ul li {
  width: 100%;
  list-style: none;
  margin: 0;
  padding: 0.5rem;
  position: relative;
  color: #000;
  font-weight: 500;
  font-size: 1rem;
  cursor: pointer;
}

[data-id="anchor-el"] ul li:hover {
  color: #f00;
}
<a href="https://stackoverflow.com" id="anchor-el"> Anchor </a>

<div>

  <div type="context" data-id="anchor-el">
    <ul>
      <li label="Open in new tab" id="newTab">Open in new tab</li>
      <li label="Open in new window" id="newWin">Open in new window</li>
    </ul>
  </div>

</div>

If you want to have Open In New Tab and Open In New Window options in the menu, why just use HTML?

<html>
  <head></head>
  <body>
    <a href="https://stackoverflow.com" id="anchor-el" target="_blank" title="If you run this snippet and click on this link, it won't work because you need to run it in your own editor"> Anchor </a>
  </body>
</html>

The above code will open in a new tab whenever clicked. Also there will be an option for Opening in a new Tab and Opening in a new window, when it is right clicked.

The attribute "target" specifies where the link will be opened; Below are some examples:

target="_blank" - "Opens in new tab"
target="_self" - "Opens in the same tab"
target="_parent" - "Opens in the parent frame"
target="_top" - "Opens in the full body of the window"

Opening native system context menus, e. g. the default right click context menu is not possible.
You can, of cause create your own context menu using jQuery for example:
https://swisnl.github.io/jQuery-contextMenu/

As an example for how to use the library:

 $(function() {
        $.contextMenu({
            selector: '#example', 
            trigger: 'left',
            callback: function(key, options) {
                var m = "clicked: " + key;
                window.console && console.log(m) || alert(m); 
            },
            items: {
                "edit": {name: "Edit", icon: "edit"},
                "cut": {name: "Cut", icon: "cut"},
               copy: {name: "Copy", icon: "copy"},
                "paste": {name: "Paste", icon: "paste"},
                "delete": {name: "Delete", icon: "delete"},
                "sep1": "---------",
                "quit": {name: "Quit", icon: function(){
                    return 'context-menu-icon context-menu-icon-quit';
                }}
            }
        });
        
        /* prevent the default switching to the target site */
        $("#example").on("click", function(event) { 
            event.preventDefault(); 
        });
    });
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.1/jquery.contextMenu.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.1/jquery.contextMenu.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.1/jquery.ui.position.js"></script>

<a href="https://google.com" id="example">click me</a>

Related