This is a very minimalist context menu code snippet written in Vanilla JS. At the moment it isn't distributed through any package manager. Initially, the snippet was a part of the Stack Overflow question, but later was moved into this repository.
- Extremely lightweight (less than 200 lines of js code)
- Written in Vanilla JS, CSS and HTML
- Framework-independent, no third-party dependencies
- Fully customizable using plain CSS (you can add dark mode support by yourself with prefers-color-scheme)
- No effects or animations
-
Include the JS module:
import { ContextMenu } from "context_menu.mjs";
Tune the path to a file according to your environment.
-
Use
ContextMenuclass to create a new context menu:new ContextMenu({ target: document.querySelector('.js-items-with-context-menu'), items: [{ label: 'Edit', action: function () { console.log('Editing...'); } }, { label: 'Delete', action: function () { console.log('Deleting...'); } }], openCondition: function (targetElement) { console.log('beforeOpen callback'); return true; // Must return true to open the menu. }, onClose: function () { console.log('onClose callback'); } });
where:
targetis a required instance of anElementon which theContextMenulistens forcontextmenuevents.itemsis a required array of item objects in the form of{ label: "", action: function(){} }. At least one item is required.openConditionis an optional function that must return a truthy value to open the menu. PassesPointerEvent.targetof thecontextmenuevent handler as a first parameter. This callback function might be used to fetch data from an HTML element. See multiple items demo.onCloseis an optional function that is called when the menu is closed.
Only one menu can be used at a time. The behavior of creating multiple
ContextMenuobjects is unexpected.
While it's technically possible to use a context menu on a single element (i.e., one specified as the target parameter without any filtering in the
openCondition callback), typically it's designed for multiple elements. For example, this could apply to notes in a note-taking app, emails in an
email client, or similar list-based interfaces. To create a context menu for all items in a list, you should pass the container element holding the items
as the target parameter, then use the openCondition callback to filter which specific elements should trigger the menu:
new ContextMenu({
target: document.querySelector('.js-items-with-context-menu'),
openCondition: function (target) {
const matched = target.matches(".item");
const id = target.dataset.id;
// do something with the id
return matched;
}
});This technique is based on Event bubbling.
See demo directory.
It should work in any of the latest browsers.
You can fully customize the menu by passing CSS code in a css property to a constructor. The provided CSS will be loaded after
the defaults.
const menu = new ContextMenu({
css: `
// A container
ul {
background: black;
}
// An item
li {
color: white;
}
`
});