Context Menu Demo

A simple context menu demo made with vanilla JavaScript.

by velo_ninja

HTML

<div class="box"><span id="info">Right-click me</span></div>
<menu class="context-menu">
	<a href="javascript:;" class="bold">Change Color</a>
	<hr>
	<a href="javascript:;" data-color="red">Red</a>
	<a href="javascript:;" data-color="green">Green</a>
	<a href="javascript:;" data-color="blue">Blue</a>
	<hr>
	<a href="javascript:;" data-color="transparent">Reset</a>
</menu>

CSS

* { margin:0; padding:0; font-family:"Lucida Grade", "Lucida Sans Unicode", sans-serif; }
body { font-size:10.5pt; background-color:#DDD; }
.box { position:absolute; top:40%; left:50%; width:256px; height:256px; margin:-128px 0 0 -128px; border:1px solid #AAA; border-radius:10px; -webkit-transition:background-color .5s ease; transition:background-color .5s ease; }
.box span { position:absolute; bottom:-1.5em; left:0; right:0; font-size:inherit; text-align:center; color:#666; text-shadow:0 1px 0 #FFF; }
.context-menu {
	display: none;
	min-width: 150px;
	position: fixed;
	z-index: 900;
	padding:5px 0;
	background: #fff;
    border: 1px solid #CCC;
	border-radius: 5px;
	box-shadow: 0 8px 20px rgba(0, 0, 0, .4);
	font-weight: normal;
}
.context-menu.shown { display:block; }
.context-menu a {
	display: block;
	padding: 3px 16px;
	overflow: hidden;
	text-decoration: none;
	text-overflow: ellipsis;
	line-height: 16px;
	white-space: nowrap;
	font-size: 10.5pt;
	font-weight: normal;
	color: #333;
	cursor: default;
}
.context-menu a.bold { font-weight:bold; }
.context-menu a.disabled { color:#B7B7B7; }
.context-menu a:not(.disabled):hover {
	color: #FFF;
    background-color:#1D5DF3;
	background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#5f87f8), color-stop(100%,#1d5df3));
	background-image:linear-gradient(to bottom, #5f87f8 0%,#1d5df3 100%);
}
.context-menu a > img {
	float: left;
	margin-right: 5px;
	width: 16px;
	height: 16px;
	overflow: hidden;
}
.context-menu hr {
	border: 0;
	height: 1px;
	margin: 5px 1px;
	background: #EEE;
}

JavaScript

document.querySelector(".box").addEventListener("contextmenu", function (e) {
	e.preventDefault();
	var contextMenu = document.querySelector(".context-menu");
		posX = (e.clientX + 150 > document.documentElement.clientWidth) ? e.clientX - 150 : e.clientX,
		posY = (e.clientY + 140 + 55 > document.documentElement.clientHeight) ? e.clientY - 140 : e.clientY;
	contextMenu.style.top = posY + "px";
	contextMenu.style.left = posX + "px";
	contextMenu.classList.add("shown");
});

document.querySelector(".context-menu").addEventListener("click", function (e) {
	var target = e.target;
	if (target.nodeName !== "A") return;
	var color = target.getAttribute("data-color");
	if (!color) return;
	var info = target.textContent;
	document.querySelector(".box").style.backgroundColor = color;
	document.querySelector("#info").textContent = "You clicked " + info;
	this.classList.remove("shown");
});

document.addEventListener("click", function (e) {
	var target = e.target;
	while (target.nodeType !== Node.DOCUMENT_NODE) {
		if (target.classList.contains("shown")) return;
		else target = target.parentNode;
	}
	var elems2hide = document.querySelectorAll(".shown");
	for (var i = 0, length = elems2hide.length; i < length; i++) {
		elems2hide[i].classList.remove("shown");
	}
});