I wanted to build a context menu for a Leaflet map.

That sounded trivial as Leaflet exposes a contextmenu event. Fits perfectly the need: fires on right click or long touch, disables browser native context menu. The trouble came from not finding how to tell what menu items to include.

Turns out there is no native way, it’s just an event and then DIY menu. There exists a plugin that does it so it looks like a context menu. But I wanted to avoid the additional dependency, and preferred something fully different from the native context menu than almost like it (if it were exactly like it I would have taken it).

Instead a added a popup on the map, with my menu items as links in a list. Works for my case, but if any other popup is open opening the context menu would close previous popup.

let map = L.map(this.element).setView(initialPosition, 13);

map.on('contextmenu', event => {
  // position where user right clicked / long pressed
  let latlng = event.latlng;

  let items = document.createElement('ul');
  let popup = L.popup()
    .setLatLng(event.latlng)
    .setContent(items)
    .openOn(map); // openOn => popup is closed if another popup is opened

  // build elements in the popup + close popup on action
  let item = document.createElement('li');
  items.appendChild(item);
  let link = document.createElement('a');
  item.appendChild(addMarkerLink);
  link.textContent = 'Do stuff';
  link.href = "#";
  link.addEventListener('click', e => {
    this.scene.add(new Marker(event.latlng.lat, event.latlng.lng));
    popup.remove();
    e.preventDefault();
  }, false);
});