Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Aug 28

The essential guide to creating custom context menus in JavaScript

The essential guide to creating custom context menus in JavaScript
Автор:
Источник:
Просмотров:
1222

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:

  1. Understanding context menus
  2. Create a basic context menu and apply styling
  3. Define variables and add JavaScript code
  4. Create helper functions
  5. Adding event listeners
  6. Handling click events
  7. 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 🙏😇

Похожее
Feb 26, 2023
Author: Ian Segers
Error handling with Async/Await in JS This will be a small article, based on some issues I picked up during code reviews and discussions with other developers. This article is rather focused on the novice JS developers. A Simple Try...
Sep 2
Author: Kostiantyn Bilous
Imagine a situation where you are working on an extensive financial application that processes thousands of transactions per minute. You discover that the system's performance has sharply declined at some point, and users begin to complain about delays. Upon analysis,...
27 мая
Автор: Марина Александровна
Уверены, что вопросы на собеседовании frontend — настоящая боль? Мы взяли на себя поиск наиболее популярных и дали на них развёрнутые ответы. Казалось бы, вопросы на собеседовании frontend разработчика Junior не должны отличаться от стандартных задачек с IT-сайтов. Даже мы...
Sep 1
If you’re a developer faced with the decision of selecting between Windows Presentation Foundation (WPF) and Windows Forms (WinForms) commonly referred to as WPF vs WinForms, you may be eager to understand the distinctions between these two UI frameworks. In...
Написать сообщение
Тип
Почта
Имя
*Сообщение
RSS
Если вам понравился этот сайт и вы хотите меня поддержать, вы можете
Сравнение REST и GraphQL
Выгорание эволюционирует. Что такое «тихий уход» — новый тренд среди офисных сотрудников
Почему вы никогда не должны соглашаться на собеседования с программированием
Типичные взаимные блокировки в MS SQL и способы борьбы с ними
GraphQL решает кучу проблем — рассказываем, за что мы его любим
9 главных трендов в разработке фронтенда в 2024 году
Из интровертов в менторы: как мидлы становятся сеньорами
NULL в SQL: что это такое и почему его знание необходимо каждому разработчику
Модуль, пакет, библиотека, фреймворк: разбираемся в разнице
Универсальный ускоритель инженера: как расти быстрее с помощью проектов
LinkedIn: Sergey Drozdov
Boosty
Donate to support the project
GitHub account
GitHub profile