mapbox-gl-contextmenu
v1.6.0
Published
A contextmenu plugin for Mapbox GL JS
Maintainers
Readme
mapbox-gl-contextmenu
A context menu plugin for Mapbox GL JS and MapLibre GL JS.
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-contextmenuCDN
<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 tofalse.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
ContextMenuItemoptions, plus: showDelay- delay in ms before showing the submenu on hover. Defaults to300.hideDelay- delay in ms before hiding the submenu when mouse leaves. Defaults to200.
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
