Skip to content

aratcliffe/mapbox-gl-contextmenu

Repository files navigation

mapbox-gl-contextmenu

A context menu plugin for Mapbox GL JS and MapLibre GL JS.

Context menu example showing menu items and submenu
View Demo

Features

  • Context menus for the entire map or scoped to specific layers.
  • Menu items, section labels, separators, and nested submenus.
  • Customizable items with start/end content slots.
  • Click handlers receive map event data.
  • Full keyboard navigation.
  • Light and dark themes.

Table of Contents

Installation

npm

npm install mapbox-gl-contextmenu

CDN

<link
  rel="stylesheet"
  href="https://unpkg.com/mapbox-gl-contextmenu@1/dist/style.css"
/>
<script src="https://unpkg.com/mapbox-gl-contextmenu@1/dist/index.umd.js"></script>

Or using jsDelivr:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/mapbox-gl-contextmenu@1/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/mapbox-gl-contextmenu@1/dist/index.umd.js"></script>

Usage

Using modules

import mapboxgl from "mapbox-gl";
import { MapboxContextMenu, ContextMenuItem } from "mapbox-gl-contextmenu";
import "mapbox-gl-contextmenu/style.css";

const map = new mapboxgl.Map({
  /* ... */
});

const menu = new MapboxContextMenu({ theme: "auto", width: 180 });

const centerItem = new ContextMenuItem({
  label: "Center map here",
  start: { className: "fa-solid fa-crosshairs" }
});

centerItem.on("click", ({ map, lngLat }) => {
  map.flyTo({ center: [lngLat.lng, lngLat.lat] });
});

menu.addItem(centerItem);
menu.addTo(map);

Using a CDN

When using the UMD build via a script tag, the library extends the mapboxgl global object:

<script>
  const { MapboxContextMenu, ContextMenuItem } = mapboxgl;

  const menu = new MapboxContextMenu({ theme: "auto", width: 180 });

  const centerItem = new ContextMenuItem({
    label: "Center map here",
    start: { className: "fa-solid fa-crosshairs" }
  });

  centerItem.on("click", ({ map, lngLat }) => {
    map.flyTo({ center: [lngLat.lng, lngLat.lat] });
  });

  menu.addItem(centerItem);
  menu.addTo(map);
</script>

API

For complete API documentation, see the API Reference.

MapboxContextMenu

The main context menu class for Mapbox GL JS and MapLibre GL JS maps.

const menu = new MapboxContextMenu(options);

Options:

  • theme - theme to use: 'light', 'dark', or 'auto' (follows system preference). Defaults to 'auto'.
  • width - menu width as a CSS value (e.g., '200px') or number in pixels.
  • className - custom CSS class name for the menu element.

Methods:

  • addItem(item) - add a menu item.
  • insertItem(index, item) - insert a menu item at a specific index.
  • removeItem(item) - remove a menu item.
  • addTo(map, target?) - add the menu to a map. Optionally restrict to specific layer(s). See Layer Targeting.
  • remove() - remove the menu from the map.

Events:

show

Fired when the context menu is displayed.

Type: ContextMenuEvent

menu.on("show", (e) => {
  console.log(`Menu opened at ${e.lngLat.lng}, ${e.lngLat.lat}`);
});

hide

Fired when the context menu is closed.

Type: ContextMenuEvent

menu.on("hide", (e) => {
  console.log("Menu closed");
});

ContextMenuItem

A clickable menu item with optional content slots.

const item = new ContextMenuItem({
  label: "Copy coordinates",
  start: { className: "fa-solid fa-copy" }
});

item.on("click", ({ lngLat, map, point, features }) => {
  // Handle click
});

Options:

  • label - a text label to display.
  • start - content to display before the label. See Slot Content.
  • end - content to display after the label. See Slot Content.
  • disabled - whether the item is disabled. Defaults to false.
  • className - custom CSS class for the <li> element.
  • buttonClassName - custom CSS class for the <button> element.

Properties:

  • label - get/set the label text.
  • start - get/set the start slot content.
  • end - get/set the end slot content.
  • disabled - get/set the disabled state.

Events:

click

Fired when the menu item is clicked.

Type: ContextMenuItemEvent

item.on("click", (e) => {
  console.log(`Clicked at ${e.lngLat.lng}, ${e.lngLat.lat}`);
});

ContextMenuSubmenu

A menu item that displays a nested submenu on hover or click.

const submenu = new ContextMenuSubmenu({
  label: "More options",
  start: { className: "fa-solid fa-ellipsis" }
});

submenu.addItem(new ContextMenuItem({ label: "Option A" }));
submenu.addItem(new ContextMenuItem({ label: "Option B" }));

Options:

  • All ContextMenuItem options, plus:
  • showDelay - delay in ms before showing the submenu on hover. Defaults to 300.
  • hideDelay - delay in ms before hiding the submenu when mouse leaves. Defaults to 200.

Methods:

  • addItem(item) - add an item to the submenu.
  • insertItem(index, item) - insert an item at a specific index.
  • removeItem(item) - remove an item from the submenu.

ContextMenuLabel

A non-interactive text label for grouping menu items into sections.

menu.addItem(new ContextMenuLabel({ text: "Navigation" }));
menu.addItem(new ContextMenuItem({ label: "Center map here" }));
menu.addItem(new ContextMenuItem({ label: "Zoom in" }));

Options:

  • text - the text to display.
  • className - custom CSS class for the label element.

ContextMenuSeparator

A horizontal line for visually grouping menu items.

menu.addItem(new ContextMenuItem({ label: "Edit" }));
menu.addItem(new ContextMenuSeparator());
menu.addItem(new ContextMenuItem({ label: "Delete" }));

Options:

  • className - custom CSS class for the separator element.

ContextMenuEvent

Fired by MapboxContextMenu.

Property Type Description
type "show" | "hide" The event type.
target MapboxContextMenu The context menu that fired the event.
map Map The Mapbox GL or MapLibre GL map instance.
lngLat { lng: number, lat: number } Geographic coordinates of the original right-click.
point { x: number, y: number } Pixel coordinates relative to the map container.
features Feature[] Features at the click location (when menu is layer-scoped).
originalEvent MouseEvent The original DOM event.

ContextMenuItemEvent

Fired by ContextMenuItem.

Property Type Description
type "click" The event type.
target ContextMenuItem The menu item that fired the event.
map Map The Mapbox GL or MapLibre GL map instance.
lngLat { lng: number, lat: number } Geographic coordinates of the original right-click.
point { x: number, y: number } Pixel coordinates relative to the map container.
features Feature[] Features at the click location (when menu is layer-scoped).
originalEvent MouseEvent The original DOM click event.

Slots

The start and end slots accept three types of content:

String

Rendered as text content:

new ContextMenuItem({
  label: "Rating",
  end: "★★★"
});

HTMLElement

For full control, pass a DOM element directly:

const icon = document.createElement("i");
icon.className = "fa-solid fa-star";

new ContextMenuItem({
  label: "Favorite",
  start: icon
});

Object Notation

Create elements declaratively:

new ContextMenuItem({
  label: "Favorite",
  start: { className: "fa-solid fa-star" }
});

Object notation supports:

  • as - element type to create. Defaults to 'span'.
  • className - CSS class name(s) to apply.
  • content - text content for the element.
  • onClick - click event handler.
new ContextMenuItem({
  label: "Settings",
  start: { as: "i", className: "fa-solid fa-gear" },
  end: { content: "Beta", className: "badge" }
});

Layer Targeting

Context menus can be scoped to specific map layers, so they only appear when the contextmenu event is triggered on features in those layers.

Pass a layer ID or array of layer IDs to addTo():

// Single layer
menu.addTo(map, "building");

// Multiple layers
menu.addTo(map, ["building", "building-outline"]);

When the menu is triggered, the features property in the click event will contain one or more features at that location:

item.on("click", ({ features }) => {
  if (features && features.length > 0) {
    console.log(features[0].properties);
  }
});

Featureset Targeting (Mapbox GL JS v3.9.0+)

Mapbox GL JS v3.9.0 introduced expanded targeting options, through the Interactions API, that allow you to target featuresets in imported basemaps like Mapbox Standard:

menu.addTo(map, { featuresetId: "buildings", importId: "basemap" });

You can also target layers using this notation:

menu.addTo(map, { layerId: "my-custom-layer" });

The library automatically detects whether these options are available and falls back to the traditional layer-based approach for older versions or MapLibre GL JS.

Keyboard Navigation

The menu supports full keyboard navigation:

  • Arrow down/up - move focus between items
  • Arrow right - open a submenu when the submenu item is focused
  • Arrow left - close submenu and return to parent
  • Enter/space - activate the focused item
  • Escape - close the menu

Theming

The menu supports light and dark themes via the theme option. Use 'auto' to follow the user's system preference.

Custom styling can be applied via the className options on each component, or by overriding the CSS custom properties:

Variable Description Light Default Dark Default
--context-menu-bg Menu background color white #141414
--context-menu-font-family Menu font family Inherited from map Inherited from map
--context-menu-border-radius Menu border radius 5px 5px
--context-menu-min-width Menu minimum width 200px 200px
--context-menu-item-text-color Item text color black white
--context-menu-item-font-size Item font size 13px 13px
--context-menu-item-focus-bg Focused item background #e8e8e8 #444444
--context-menu-item-active-bg Active item background #f3f3f3 #2a2a2a
--context-menu-item-disabled-opacity Disabled item opacity 0.5 0.5
--context-menu-button-height Button height 30px 30px
--context-menu-button-radius Button border radius 2.5px 2.5px
--context-menu-separator-color Separator line color #e8e8e8 #505050

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors