Step-by-step guide to creating custom context menus (right-click menu) in JavaScript.
Hello Developers 👋,
A context menu, also known as a right-click menu or pop-up menu, is a menu that appears when the user performs a specific action, such as right-clicking on an object or pressing and holding on a touch screen. The context menu displays a list of options that are relevant to the selected object or area of the user interface.
In a web application, a context menu can also be implemented to provide users with additional options or commands.
However, since mobile devices have no built-in right-click functionality, web developers often implement context menus using a long press or tap-and-hold gesture.
To create a context menu in a web application, developers can use JavaScript and CSS to display a pop-up menu when the user performs the designated gesture.
The menu can include options for performing actions such as copying and pasting text, opening a link in a new tab, or deleting an item from a list.
In addition, web developers can customize context menus to match the design and branding of their applications.
This can be achieved through the use of custom CSS styles and by incorporating icons or graphics that are consistent with the overall look and feel of the application.
So today, we will discuss how to create custom context menus in JavaScript.
We will cover the following topics:
- Understanding context menus
- Create a basic context menu and apply styling
- Define variables and add JavaScript code
- Create helper functions
- Adding event listeners
- Handling click events
- Conclusion
So, let’s get started!
👉 Understanding context menus
Before we dive into the code, let’s take a moment to understand how context menus work. When you right-click on an element on a web page, the browser creates a “contextmenu” event. This event contains information about the position of the mouse cursor and the element that was clicked.
To create a custom context menu, we need to prevent the default context menu from appearing and replace it with our own menu.
We can do this by creating an HTML element that will serve as our context menu, positioning it at the mouse cursor, and showing it when the “contextmenu” event is triggered.
• • •
💡 Speed up your blog creation with DifferAI.
Available for free exclusively on the free and open blogging platform, Differ.
• • •
👉 Creating a basic context menu and applying styling
To create a basic context menu, we will start by creating an HTML element that will serve as our menu.
We will position this element using CSS and set its display property to “none” so that it is hidden by default.
Note: I have used TailwindCSS for styling a context menu and also apply some custom CSS.
Add <script>
into <head>
tag of your file.
<script src="https://cdn.tailwindcss.com"></script>
Add below HTML code into <body>
tag of your HTML file.
<!-- Context Menu -->
<div class="context-menu">
<div class="bg-white w-60 border border-gray-300 rounded-lg flex flex-col text-sm py-4 px-2 text-gray-500 shadow-lg">
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer">
<div class="w-5 text-gray-900">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM10.5 7.5v6m3-3h-6"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-4">Zoom</div>
</div>
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer">
<div class="w-5 text-gray-900">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM13.5 10.5h-6"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-4">Zoom Out</div>
</div>
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer" onclick="fullscreen()">
<div class="w-5 text-gray-900">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path
d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-3">Full Screen</div>
</div>
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer">
<div class="w-5 text-gray-900">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path
d="M7.217 10.907a2.25 2.25 0 100 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186l9.566-5.314m-9.566 7.5l9.566 5.314m0 0a2.25 2.25 0 103.935 2.186 2.25 2.25 0 00-3.935-2.186zm0-12.814a2.25 2.25 0 103.933-2.185 2.25 2.25 0 00-3.933 2.185z"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-3">Share</div>
</div>
<hr class="my-3 border-gray-300" />
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer">
<div class="w-5 text-gray-900 font-bold">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path d="M19.5 12h-15m0 0l6.75 6.75M4.5 12l6.75-6.75" stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-3">Go Back</div>
</div>
<div class="flex hover:bg-gray-100 py-1 px-2 rounded cursor-pointer">
<div class="w-5 text-gray-900">
<svg aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path
d="M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 11-6 0H5.25A2.25 2.25 0 003 12m18 0v6a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 18v-6m18 0V9M3 12V9m18 0a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 9m18 0V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v3"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="ml-3">Add to Wallet</div>
</div>
</div>
</div>
<!-- Context Menu -->
Next, we apply some styling to hide the menu we created.
<style>
.context-menu {
display: none;
position: absolute;
z-index: 10;
}
</style>
👉 Define variables and add JavaScript code
So, now we add javascript code for the working context menu.
var menu = document.querySelector(".context-menu");
var menuState = 0;
var contextMenuActive = "block";
We have created menu
variable for targeting .context-menu
element for DOM.
menuState
is a flag for tracks whether the menu is open or not.
contextMenuActive
is a variable for applying CSS Class when we display the menu. It will add CSS display: block
to the menu.
👉 Create helper functions
The use of helper functions can improve the overall performance of a program by reducing the amount of duplicated code and making the program more efficient.
They can also make the code more modular and easier to test and debug.
So, we need to create the following helper functions:
- For open context menu (Menu On)
- For close context menu (Menu Off)
- Get the position of the right-click in a window
- Position the context menu in the proper position where the right click perform in the window
💻 For open context menu (Menu On)
// Turns the custom context menu on.
function toggleMenuOn() {
if (menuState !== 1) {
menuState = 1;
menu.classList.add(contextMenuActive);
}
}
💻 For close context menu (Menu Off)
// Turns the custom context menu off.
function toggleMenuOff() {
if (menuState !== 0) {
menuState = 0;
menu.classList.remove(contextMenuActive);
}
}
Note: Here I used the flag variable menuState
for checking whether the context menu is open or not.
💻 Get the position of the right-click in the window
// Get the position of the right-click in window and returns the X and Y coordinates
function getPosition(e) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx =
e.clientX +
document.body.scrollLeft +
document.documentElement.scrollLeft;
posy =
e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
x: posx,
y: posy
};
}
Here we get the position of the right click in the window and return the X and Y coordinates where the user performs the right click.
💻 Position the context menu in the proper position where the right click performs in the window
// Position the Context Menu in right position.
function positionMenu(e) {
let clickCoords = getPosition(e);
let clickCoordsX = clickCoords.x;
let clickCoordsY = clickCoords.y;
let menuWidth = menu.offsetWidth + 4;
let menuHeight = menu.offsetHeight + 4;
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
if (windowWidth - clickCoordsX < menuWidth) {
menu.style.left = windowWidth - menuWidth + "px";
} else {
menu.style.left = clickCoordsX + "px";
}
if (windowHeight - clickCoordsY < menuHeight) {
menu.style.top = windowHeight - menuHeight + "px";
} else {
menu.style.top = clickCoordsY + "px";
}
}
Here positionMenu
function calculates the coordinates returned by getPosition
function and it will position the context menu in the proper way.
👉 Adding event listeners
Now we add an Event listener for the context menu when user performs a right click.
Add the below code to your script file
// Event Listener for window ContextMenu Event - When Right Click is clicked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
toggleMenuOn();
positionMenu(event);
});
👉 Handling click events
We need to handle click events because:
- When a user clicks outside of the window the menu should be closed.
- When a user clicks the Esc button from the keyboard the menu should be closed.
// Event Listener for Close Context Menu when outside of menu clicked
document.addEventListener("click", (e) => {
var button = e.which || e.button;
if (button === 1) {
toggleMenuOff();
}
});
// Close Context Menu on Esc key press
window.onkeyup = function (e) {
if (e.keyCode === 27) {
toggleMenuOff();
}
}
💻 Final code
To wrap all the code we have created a custom Context Menu using JavaScript.
var menu = document.querySelector(".context-menu");
var menuState = 0;
var contextMenuActive = "block";
// Method to turn on fullscreen of current window
function fullscreen() {
document.documentElement.requestFullscreen();
}
// Event Listener for window ContextMenu Event - When Right Click is clicked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
toggleMenuOn();
positionMenu(event);
});
// Turns the custom context menu on.
function toggleMenuOn() {
if (menuState !== 1) {
menuState = 1;
menu.classList.add(contextMenuActive);
}
}
// Turns the custom context menu off.
function toggleMenuOff() {
if (menuState !== 0) {
menuState = 0;
menu.classList.remove(contextMenuActive);
}
}
// Get the position of the right click in window and returns the X and Y coordinates
function getPosition(e) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx =
e.clientX +
document.body.scrollLeft +
document.documentElement.scrollLeft;
posy =
e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
x: posx,
y: posy
};
}
// Position the Context Menu in right position.
function positionMenu(e) {
let clickCoords = getPosition(e);
let clickCoordsX = clickCoords.x;
let clickCoordsY = clickCoords.y;
let menuWidth = menu.offsetWidth + 4;
let menuHeight = menu.offsetHeight + 4;
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
if (windowWidth - clickCoordsX < menuWidth) {
menu.style.left = windowWidth - menuWidth + "px";
} else {
menu.style.left = clickCoordsX + "px";
}
if (windowHeight - clickCoordsY < menuHeight) {
menu.style.top = windowHeight - menuHeight + "px";
} else {
menu.style.top = clickCoordsY + "px";
}
}
// Event Listener for Close Context Menu when outside of menu clicked
document.addEventListener("click", (e) => {
var button = e.which || e.button;
if (button === 1) {
toggleMenuOff();
}
});
// Close Context Menu on Esc key press
window.onkeyup = function (e) {
if (e.keyCode === 27) {
toggleMenuOff();
}
}
Working demo
Conclusion
We have discussed how to create custom context menus in JavaScript. We started by understanding how context menus work and then created a basic context menu using HTML, CSS, and JavaScript.
We handled click events and performed actions based on the selected menu item.
Custom context menus can be a useful addition to your website or web application, allowing users to perform actions quickly and easily.
By following the steps outlined in this blog post, you can create your own custom context menus in JavaScript.
Thanks for reading 🙏😇