context menu

Make context menu by Vanilla Javascript

In this lesson, we show you the way to make a beautiful context menu built with Vanilla JavaScript and CSS that replaces the default browser right click menu and comes with a smooth pop-up animation based on CSS3 transitions and transforms.

First at all, you create an html page and write the following html code inside body tag:

<menu class="menu">
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-folder-open"></i> <span class="menu-text">Open</span> </button>
  </li>
  <li class="menu-item disabled">
    <button type="button" class="menu-btn"> <span class="menu-text">Open in New Window</span> </button>
  </li>
  <li class="menu-separator"></li>
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-reply"></i> <span class="menu-text">Reply</span> </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-star"></i> <span class="menu-text">Favorite</span> </button>
  </li>
  <li class="menu-item submenu">
    <button type="button" class="menu-btn"> <i class="fa fa-users"></i> <span class="menu-text">Social</span> </button>
    <menu class="menu">
      <li class="menu-item">
        <button type="button" class="menu-btn"> <i class="fa fa-comment"></i> <span class="menu-text">Comment</span> </button>
      </li>
      <li class="menu-item submenu">
        <button type="button" class="menu-btn"> <i class="fa fa-share"></i> <span class="menu-text">Share</span> </button>
        <menu class="menu">
          <li class="menu-item">
            <button type="button" class="menu-btn"> <i class="fa fa-twitter"></i> <span class="menu-text">Twitter</span> </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn"> <i class="fa fa-facebook-official"></i> <span class="menu-text">Facebook</span> </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn"> <i class="fa fa-google-plus"></i> <span class="menu-text">Google Plus</span> </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn"> <i class="fa fa-envelope"></i> <span class="menu-text">Email</span> </button>
          </li>
        </menu>
      </li>
    </menu>
  </li>
  <li class="menu-separator"></li>
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-download"></i> <span class="menu-text">Save</span> </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-edit"></i> <span class="menu-text">Rename</span> </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn"> <i class="fa fa-trash"></i> <span class="menu-text">Delete</span> </button>
  </li>
</menu>

Next, you need to include the following css file inside the head tag:

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

This css will make your menu more beautiful with fancy font.

Now, you need to style your menu by css. Here are the codes:

.menu {
  position: absolute;
  width: 200px;
  padding: 2px;
  margin: 0;
  border: 1px solid #bbb;
  background: #eee;
  background: -webkit-linear-gradient(to bottom, #fff 0%, #e5e5e5 100px, #e5e5e5 100%);
  background: linear-gradient(to bottom, #fff 0%, #e5e5e5 100px, #e5e5e5 100%);
  z-index: 100;
  border-radius: 3px;
  box-shadow: 1px 1px 4px rgba(0,0,0,.2);
  opacity: 0;
  -webkit-transform: translate(0, 15px) scale(.95);
  transform: translate(0, 15px) scale(.95);
  transition: transform 0.1s ease-out, opacity 0.1s ease-out;
  pointer-events: none;
}

.menu-item {
  display: block;
  position: relative;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.menu-btn {
  background: none;
  line-height: normal;
  overflow: visible;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  display: block;
  width: 100%;
  color: #444;
  font-family: 'Roboto', sans-serif;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  border: 1px solid transparent;
  white-space: nowrap;
  padding: 6px 8px;
  border-radius: 3px;
}
 .menu-btn::-moz-focus-inner, .menu-btn::-moz-focus-inner {
 border: 0;
 padding: 0;
}

.menu-text { margin-left: 25px; }

.menu-btn .fa {
  position: absolute;
  left: 8px;
  top: 50%;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
}

.menu-item:hover > .menu-btn {
  color: #fff;
  outline: none;
  background-color: #2E3940;
  background: -webkit-linear-gradient(to bottom, #5D6D79, #2E3940);
  background: linear-gradient(to bottom, #5D6D79, #2E3940);
  border: 1px solid #2E3940;
}

.menu-item.disabled {
  opacity: .5;
  pointer-events: none;
}

.menu-item.disabled .menu-btn { cursor: default; }

.menu-separator {
  display: block;
  margin: 7px 5px;
  height: 1px;
  border-bottom: 1px solid #fff;
  background-color: #aaa;
}

.menu-item.submenu::after {
  content: "";
  position: absolute;
  right: 6px;
  top: 50%;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: #808080;
}

.menu-item.submenu:hover::after { border-left-color: #fff; }

.menu .menu {
  top: 4px;
  left: 99%;
}

.show-menu, .menu-item:hover > .menu {
  opacity: 1;
  -webkit-transform: translate(0, 0) scale(1);
  transform: translate(0, 0) scale(1);
  pointer-events: auto;
}

.menu-item:hover > .menu {
  -webkit-transition-delay: 100ms;
  transition-delay: 300ms;
}

There are some CSS properties that you need to notice:
* display: The display CSS property specifies the type of rendering box used for an element. In HTML, default display property values are taken from behaviors described in the HTML specifications or from the browser/user default stylesheet. The block value will generate a block element box.
* background: set background for element. Background can be filled by color, image, gradient. You can read more about background property at Mozilla. The CSS linear-gradient() function creates an which represents a linear gradient of colors. The result of this function is an object of the CSS data type. You can read more about linear gradient at Mozilla.
* transform/-webkit-transform: The CSS transform property lets you modify the coordinate space of the CSS visual formatting model. Using it, elements can be translated, rotated, scaled, and skewed. In some old webkit browsers, you need to user prefix -webkit-. However, if you are using the latest browsers (now – 2017), you can forget this prefix, just use transform only.
* transition-delay: The transition-delay CSS property specifies the amount of time to wait between a change being requested to a property that is to be transitioned and the start of the transition effect.
If you want to know more detail about other css properties, you can see at Mozilla CSS reference.

Finally, you write the javascript for context menu:

var menu = document.querySelector('.menu');

function showMenu(x, y){
    menu.style.left = x + 'px';
    menu.style.top = y + 'px';
    menu.classList.add('show-menu');
}

function hideMenu(){
    menu.classList.remove('show-menu');
}

function onContextMenu(e){
    e.preventDefault();
    showMenu(e.pageX, e.pageY);
    document.addEventListener('click', onClick, false);
}

function onClick(e){
    hideMenu();
    document.removeEventListener('click', onClick);
}

document.addEventListener('contextmenu', onContextMenu, false);

In above code, you have to notice:
* document.querySelector(css_selector): will return the DOM has specific css selector. In this example is the DOM that has class name – menu.
* The function showmenu will show the menu at position (x, y). You just add the class name for menu and this class name was styled in CSS file.
* The function hidemenu will remove the class name that was added by showmenu.
* The document.addEventListener('contextmenu', func, false): will add event on context menu. In fact, it calls the showmenu function and add click event to menu.
* preventDefault: disable default context menu.
* The document.removeEventListener('click', func) will remove click event from menu after it was chosen.

Now, you have a fancy context menu to replace the default context menu.