DEV Community

Cover image for Make a Custom Right Click Menu with Javascript
Ramiro - Ramgen
Ramiro - Ramgen

Posted on

Make a Custom Right Click Menu with Javascript

Video version if you want to see it.
Give it a like 😁

Alright let's see how to make a custom menu.
We are going to use vanilla javascript, but you can easily use this to make it on react or vue or other framework of your choosing.

This one is going to be short and sweet for those that just wants the result 😁

First we'll have the menu itself.

<body>
  <div class="app" id="app">
    <ul class="menu hide" id="menu">
      <li class="menuItem"><span>🎵</span>Play</li>
      <li class="Separator"></li>
      <li class="menuItem"><span></span>Next</li>
      <li class="menuItem"><span></span>Stop</li>
      <li class="menuItem"><span></span>Last</li>
      <li class="Separator"></li>
      <li class="menuItem"><span></span>Record</li>
      <li class="menuItem"><span>🔄</span>Reload</li>
      <li class="Separator"></li>
      <li class="menuItem"><span>🗑️</span>Discard</li>
    </ul>
  </div>
</body>
Enter fullscreen mode Exit fullscreen mode

Then we define some helper functions and we select some elements in the DOM.

el = (e) => document.querySelector(e)

const app = el('#app')
const menu = el('#menu')

let menuActive = false
menu.classList.add('hide')

const showMenu = () => {
  menu.classList.remove('hide')
  menu.classList.add('show')
}

const hideMenu = () => {
  menu.classList.add('hide')
  menu.classList.remove('show')
}
Enter fullscreen mode Exit fullscreen mode

We have a function to select elements, a flag for the state, then two functions one to show the menu and one to hide it, (we can do this with a toggle function but I wanted to make things more clear, so feel free to implement that)

Now lets see where the important stuff is:

const moveMenu = (event) => {
  event.preventDefault()
  console.log(event)

  menuActive = true
  showMenu()

  let wHeight = window.innerHeight

  let scrPosX = event.clientX + window.scrollX
  let scrPosY = event.clientY + window.scrollY

  let Y_window_offset = event.clientY + menu.clientHeight - wHeight

  if (Y_window_offset > 0) {
    scrPosY -= menu.clientHeight
  }

  menu.style.left = `${scrPosX}px`
  menu.style.top = `${scrPosY}px`

  return false
}
Enter fullscreen mode Exit fullscreen mode

So what we are doing here:

  • First we prevent the default operating system menu
  • We set the menu state menuActive to active
  • We retrieve the windows inner height, this one is the height of the viewport
  • Now we calculate the coordinates of the menu click and we offset them with the scroll from both Y and X axis
  let scrPosX = event.clientX + window.scrollX
  let scrPosY = event.clientY + window.scrollY
Enter fullscreen mode Exit fullscreen mode
  • Now this one let Y_window_offset = event.clientY + menu.clientHeight - wHeight is the difference between the bottom of the menu and the bottom of the screen, we'll use this to know if the menu is going offscreen at the bottom and we can shift it up
  • We do that when that offset is positive and we substract that offset with the height of the menu.
  • Finally we set the left and top CSS positions of the menu elemnt to those coordinates, since the element is in position absolute it will move to those coordinates, note that the parent is in position relative.

Then we give this functions to the contextmenu event listener and whoala:

app.addEventListener('contextmenu', moveMenu)
app.addEventListener('click', (event) => {
  if (menuActive) {
    hideMenu()
    menuActive = false
  }
})

Enter fullscreen mode Exit fullscreen mode

We also add a event listener for a click in the app for hiding the menu.

So if you want to make this even better you can do the same shift we do for the bottom of the screen but at the right side too, because now the menu will go offscreen 😅


I will be making better content now that I have some better equipment, going to make Machine Learning, app development, Data science and General programming stuff content 😁
I'll appreciate if you give me a follow, also if you have time check out my youtube channel ramgendeploy drop a sub if you like there 😄


CSS for the braves (jk)

@import url("https://fonts.googleapis.com/css?family=Open+Sans&display=swap");
* {
  box-sizing: content-box;
}

body {
  margin: 0;
  font-family: "Open Sans", sans-serif;
  position: relative;
  background: #151515;
}

.app {
  background: #202020;
  width: 80%;
  margin: 0 auto;
  height: fit-content;
  color: white;
  padding: 15px;
  line-height: 30px;
}

.hide {
  display: none;
}

.show {
  display: block;
}

.menu {
  margin: 0;
  color: black;
  border: solid black 1px;
  position: absolute;
  width: 250px;
  background: white;
  padding: 10px 0px;
  border-radius: 4px;
}

.Separator {
  display: block;
  height: 1px;
  background: #7e7b7b;
  margin: 5px 10px;
  user-select: none;
}

.menuItem {
  display: grid;
  grid-template-columns: 30px auto;
  align-items: center;
  padding: 7px 15px 7px 8px;
  user-select: none;
  cursor: pointer;
}

.menuItem:hover {
  background: lightblue;
  transition: 500ms;
}

.menuItem:active {
  background: cadetblue;
  transition: 500ms;
}

.imgL {
  float: left;
  padding: 10px;
}

.imgR {
  float: right;
  padding: 10px;
}

.slime {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  background: #202020;
  padding: 10px;
  border-bottom: 3px solid #303030;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
naveennamani profile image
naveennamani

I once implemented this functionality in a small personal webapp, where the menu items will change based on the element you're clicking. I used some custom properties on the elements and based on that the menu items will dynamically load on right click.

It was fun to build, and the info about css positioning is straight to the point. Informative article

Collapse
 
ramgendeploy profile image
Ramiro - Ramgen

Yea this is a really cool small project to start with javascript, did you use react or just javascript

Collapse
 
naveennamani profile image
naveennamani

I used HTML custom elements while I was learning about them at that time along with vanilla js

Thread Thread
 
ramgendeploy profile image
Ramiro - Ramgen

That's great, I want to do this on react but would be really similar maybe on a full app I'll do it

Collapse
 
muhammadraihan27 profile image
Muhammad Raihan

Awesome

Collapse
 
ramgendeploy profile image
Ramiro - Ramgen

Thanks! 😁

Collapse
 
ramgendeploy profile image
Ramiro - Ramgen

Thanks 😁