Add custom marker to a MapLibre GL (an open-source fork of Mapbox GL) map

You have 2 options when you want to draw locations on a MapLibre GL map: add locations as a layer or as separate markers.

In this code sample, we would like to show how to add custom markers and handle marker events. The full version of the code sample you can find on JSFiddle.

1. Get custom icons

You can design your own map marker icon with the Marker Icon API playground or use any other icon.

2. Add a marker with custom icons

The MapLibre GL allows defining custom DIV-elements for a marker. Just create a new DIV-element and use it when a marker is created. You can setup the marker icon with below CSS. Explicitly set scaleFactor=2 in the Marker Icon API call and background-size style to contain to get better Marker Icon quality with MapLibre GL

.airport {
  height: 69px;
  width: 47px;
  background-image: url(https://api.geoapify.com/v1/icon/?type=awesome&scaleFactor=2&color=%2372a2d4&size=x-large&icon=plane-departure&apiKey=YOUR_API_KEY);
  background-size: contain;
  cursor: pointer;
}
// Zürich Airport, icon size: 47 x 69px, shadow adds: 6px
// lat: 47.46101649104483, lon: 8.551922366826949
var airportIcon = document.createElement('div');
airportIcon.classList.add("airport");

var airport = new Marker(airportIcon, {
    anchor: 'bottom',
    offset: [0, 6]
  })
  .setLngLat([8.551922366826949, 47.46101649104483])
  .addTo(map);

Or set all properties dynamically:

// Zürich main Train Station, icon size: 38 x 55px, shadow adds: 5px
// lat: 47.378100800080745, lon: 8.5393635
var trainStationIcon = document.createElement('div');
trainStationIcon.style.width = '38px';
trainStationIcon.style.height = '55px';
// Explicitly set scaleFactor=2 in the call 
// and backgroundSize=contain to get better 
// Marker Icon quality with MapLibre GL
trainStationIcon.style.backgroundSize = "contain";
trainStationIcon.style.backgroundImage = "url(https://api.geoapify.com/v1/icon/?type=awesome&scaleFactor=2&color=%23e68d6f&size=large&icon=train&iconSize=large&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a)";
trainStationIcon.style.cursor = "pointer";

var trainStation = new Marker(trainStationIcon, {
    anchor: 'bottom',
    offset: [0, 5]
  })
  .setLngLat([8.5393635, 47.378100800080745])
  .addTo(map);

Note, by default the marker anchor is center. So the center of your marker is attached to marker position. Change the anchor (for example, to bottom for a pin icon) to change the marker position. In addition, you need to set an offset if the marker icon contains a shadow. For example, 5px for the icon provided in this code sample.

3. Show marker popup

Create a popup and attach it to the marker. Popup state is toggled on marker click event automatically. Use setText() or setHTML() methods to specify the popup content. You can also set a className as an option to define popup appearance with CSS.

var airportPopup = new Popup({
    anchor: 'bottom',
    offset: [0, -64] // height - shadow
  })
  .setText('Zürich Airport');

var airport = new Marker(airportIcon, {
    anchor: 'bottom',
    offset: [0, 6]
  })
  .setLngLat([8.551922366826949, 47.46101649104483])
  .setPopup(airportPopup)
  .addTo(map);

Note, by default a popup is attached to the marker coordinates. Add an offset to make it appear under the marker icon.

4. Marker click, hover, and other events

Unfortunately, there is no event provided by the framework for a marker. However, as we have the DIV-element, we can handle all its events.

trainStationIcon.onclick = (event) => {
  // you can add custom logic here. For example, modify popup.
  trainStationPopup.setHTML("<h3>I'm clicked!</h3>");
}

trainStationIcon.onmouseenter = () => trainStation.togglePopup(); // show/hide popup on mouse hover
trainStationIcon.onmouseleave = () => trainStation.togglePopup();