intermediate
JavaScript
Work with markers in Mapbox.js
Prerequisite
Familiarity with front-end development concepts.

Mapbox.js is no longer in active development. To learn more about our newer mapping tools see Add custom markers in Mapbox GL JS.

In this guide, we’ll show how to add markers, customize them, and make them interactive with Mapbox.js. Think of this guide as a curated stroll through all that’s possible with markers in Mapbox.js.

Getting started

For this guide you’ll need your API access token. You can find your access token on your Account page. To better understand each example, you can copy the full source code into your own local project and experiment. We adapted many of these demos from Mapbox.js examples.

Add markers

You can add markers to your map using Leaflet or with GeoJSON using Mapbox.js.

Add markers in Leaflet

You can add a simple DOM marker to your map with L.marker. In the example below, we added a marker to the map just by knowing its coordinates. This technique is great for when you have only a few markers to add.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map-leaflet' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapLeaflet = L.mapbox.map('map-leaflet', 'mapbox.light')
  .setView([37.8, -96], 4);

L.marker([38.913184, -77.031952]).addTo(mapLeaflet);
L.marker([37.775408, -122.413682]).addTo(mapLeaflet);

mapLeaflet.scrollWheelZoom.disable();
</script>
</body>
</html>

Add markers with GeoJSON in Mapbox.js

You can also save your marker coordinates as GeoJSON and then load your GeoJSON on a map with Mapbox.js. In this example, we added the coordinates of the Mapbox D.C. and San Francisco offices to our inline GeoJSON. GeoJSON format is great for organizing features, especially when working with larger data files.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map_geo' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    }
  }
];

var mapGeo = L.mapbox.map('map_geo', 'mapbox.light')
  .setView([37.8, -96], 4);

var myLayer = L.mapbox.featureLayer().setGeoJSON(geojson).addTo(mapGeo);
mapGeo.scrollWheelZoom.disable();
</script>
</body>
</html>

You can also load GeoJSON as an external file hosted locally or on Github. In the next section, you’ll learn how to style GeoJSON markers with the simplestyle specification.

If you’re new to working with GeoJSON, here are some tools to help you generate, validate, or format GeoJSON:

Style markers

To style a marker, you can add simplestyle to your GeoJSON, load a custom image, or create your own markers with HTML and CSS.

Style markers with simplestyle

The simplestyle spec is a styling convention for GeoJSON. This means that you can add specific keys and values to each marker to change a marker’s color, symbol, and size.

Here are all the styling options available as keys and values:

Key Value Example
"marker-color" Any hex value
Example: "#3bb2d0"
Blue-colored marker
"marker-symbol" Any Maki icon name, an integer, or a lowercase letter
Example: "1"
marker with "1" symbol
"marker-size" small, medium, large
Example: "large"
large marker

In this example, we took the GeoJSON from the previous section and added simplestyle. View the source to see how the marker styles are added to each feature.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map_simple' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    },
    properties: {
      'marker-color': '#3bb2d0',
      'marker-size': 'large',
      'marker-symbol': 'rocket'
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    },
    properties: {
      'marker-color': '#3bb2d0',
      'marker-size': 'large',
      'marker-symbol': 'rocket'
    }
  }
];

var mapSimple = L.mapbox.map('map_simple', 'mapbox.light')
  .setView([37.8, -96], 4);
var myLayer = L.mapbox.featureLayer().setGeoJSON(geojson).addTo(mapSimple);
mapSimple.scrollWheelZoom.disable();
</script>
</body>
</html>

Style markers with an image

You can define a custom marker image in your GeoJSON by adding an icon object to each feature’s properties. In this example, L.icon is used to set the marker image to each feature’s iconURL.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map-one' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapOne = L.mapbox.map('map-one', 'mapbox.light')
  .setView([37.8, -96], 4);
var myLayer = L.mapbox.featureLayer().addTo(mapOne);

var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    },
    properties: {
      icon: {
        iconUrl: 'https://www.mapbox.com/mapbox.js/assets/images/astronaut1.png',
        iconSize: [50, 50], // size of the icon
        iconAnchor: [25, 25], // point of the icon which will correspond to marker's location
        popupAnchor: [0, -25], // point from which the popup should open relative to the iconAnchor
        className: 'dot'
      }
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    },
    properties: {
      icon: {
        iconUrl: 'https://www.mapbox.com/mapbox.js/assets/images/astronaut2.png',
        iconSize: [50, 50], // size of the icon
        iconAnchor: [25, 25], // point of the icon which will correspond to marker's location
        popupAnchor: [0, -25], // point from which the popup should open relative to the iconAnchor
        className: 'dot'
      }
    }
  }
];
myLayer.on('layeradd', function(e) {
  var marker = e.layer,
    feature = marker.feature;
  marker.setIcon(L.icon(feature.properties.icon));
});
myLayer.setGeoJSON(geojson);
mapOne.scrollWheelZoom.disable();
</script>
</body>
</html>

Style markers with HTML and CSS

If you’d like to customize your markers even more, you can replace the standard marker with a <div>, assign it a class, and then style it with CSS using L.divIcon. In this example, you’ll follow a similar pattern as you did when adding a marker image, but instead you’ll assign a class name to the features and then add CSS to style it.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<style>
.my-icon {
  border-radius: 100%;
  width: 20px;
  height: 20px;
  text-align: center;
  line-height: 20px;
  color: white;
}

.icon-dc {
  background: #3bb2d0;
}

.icon-sf {
  background: #3bb2d0;
}
</style>
<div id='map-two' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapTwo = L.mapbox.map('map-two', 'mapbox.light')
.setView([37.8, -96], 4);

var myLayer = L.mapbox.featureLayer().addTo(mapTwo);

var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    },
    properties: {
      icon: {
        className: 'my-icon icon-dc', // class name to style
        html: '&#9733;', // add content inside the marker, in this case a star
        iconSize: null // size of icon, use null to set the size in CSS
      }
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    },
    properties: {
      icon: {
        className: 'my-icon icon-sf', // class name to style
        html: '&#9733;', // add content inside the marker, in this case a star
        iconSize: null // size of icon, use null to set the size in CSS
      }
    }
  }
];
myLayer.on('layeradd', function(e) {
  var marker = e.layer,
    feature = marker.feature;
  marker.setIcon(L.divIcon(feature.properties.icon));
});
myLayer.setGeoJSON(geojson);

mapTwo.scrollWheelZoom.disable();
</script>
</body>
</html>

Add popups

You can add popups with simplestyle in your GeoJSON or with JavaScript.

Add popups with simplestyle

Simplestyle allows you to add popups automatically if you add title and description keys to each feature’s properties. In the example below, these fields are added to the GeoJSON. Click the markers to trigger the popup.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map-popups' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapPopups = L.mapbox.map('map-popups', 'mapbox.light')
  .setView([37.8, -96], 4);
var myLayer = L.mapbox.featureLayer().addTo(mapPopups);

var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    },
    properties: {
      title: 'Mapbox DC',
      description: '1714 14th St NW, Washington DC',
      'marker-color': '#3bb2d0',
      'marker-size': 'large',
      'marker-symbol': 'rocket'
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    },
    properties: {
      title: 'Mapbox SF',
      description: '155 9th St, San Francisco',
      'marker-color': '#3bb2d0',
      'marker-size': 'large',
      'marker-symbol': 'rocket'
    }
  }
];
myLayer.setGeoJSON(geojson);
mapPopups.scrollWheelZoom.disable();
</script>
</body>
</html>

You can add HTML to you popups by adding it to the title and description values in your GeoJSON. This allows you to add links, images, videos, lists, and other simple HTML elements to your popups.

Add popups with JavaScript

You can customize the content of each popup with the L.bindPopup method. In this example, an image key is added to each feature’s property object, and a reference to this key when is included when bindPopup() is called to make the image appear inside the popup.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<div id='map-popups-js' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapPopupsJS = L.mapbox.map('map-popups-js', 'mapbox.light')
  .setView([37.8, -96], 4);
var myLayer = L.mapbox.featureLayer().addTo(mapPopupsJS);

var geojson = [
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-77.031952, 38.913184]
    },
    properties: {
      title: 'Mapbox DC',
      description: '1714 14th St NW, Washington DC',
      image: 'https://farm9.staticflickr.com/8604/15769066303_3e4dcce464_n.jpg',
      icon: {
        iconUrl: 'https://www.mapbox.com/mapbox.js/assets/images/astronaut1.png',
        iconSize: [50, 50], // size of the icon
        iconAnchor: [25, 25], // point of the icon which will correspond to marker's location
        popupAnchor: [0, -25], // point from which the popup should open relative to the iconAnchor
        className: 'dot'
      }
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.413682, 37.775408]
    },
    properties: {
      title: 'Mapbox SF',
      description: '155 9th St, San Francisco',
      image: 'https://farm9.staticflickr.com/8571/15844010757_63b093d527_n.jpg',
      icon: {
        iconUrl: 'https://www.mapbox.com/mapbox.js/assets/images/astronaut2.png',
        iconSize: [50, 50], // size of the icon
        iconAnchor: [25, 25], // point of the icon which will correspond to marker's location
        popupAnchor: [0, -25], // point from which the popup should open relative to the iconAnchor
        className: 'dot'
      }
    }
  }
];

// Set a custom icon on each marker based on feature properties.
myLayer.on('layeradd', function(e) {
  var marker = e.layer,
    feature = marker.feature;
  marker.setIcon(L.icon(feature.properties.icon));
  var content = '<p><strong>' + feature.properties.title + '</strong></p><img src="' + feature.properties.image + '" alt="">';
  marker.bindPopup(content);
});
myLayer.setGeoJSON(geojson);
mapPopupsJS.scrollWheelZoom.disable();
</script>
</body>
</html>

More examples

You can further customize your popups with Mapbox.js. Here are more examples to get you started:

Cluster markers

For dense point data, try the Leaflet plug-in Markercluster to visualize your data. In the example below, we load an external GeoJSON file, create a clustergroup from the data, and add it to the map. Since Markercluster is a plugin, you’ll need to add additional CSS and JS to enable it.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/leaflet.markercluster.js'></script>
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.css' rel='stylesheet' />
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.Default.css' rel='stylesheet' />
<div id='map-cluster' class='map'></div>
<script>
L.mapbox.accessToken = '<your access token here>';
var mapCluster = L.mapbox.map('map-cluster')
  .setView([38.9, -77], 11)
  .addLayer(L.mapbox.tileLayer('mapbox.light'));
L.mapbox.featureLayer()
  .loadURL('/help/data/examples/stations.geojson')
  .on('ready', function(e) {
    var clusterGroup = new L.MarkerClusterGroup();
    e.target.eachLayer(function(layer) {
      clusterGroup.addLayer(layer);
    });
    mapCluster.addLayer(clusterGroup);
  });
mapCluster.scrollWheelZoom.disable();
</script>
</body>
</html>

More examples

For more ideas of what you can do with clusters in Mapbox.js, check out these examples:

Toggle layers

Finally, take a look at how to toggle layers in Mapbox.js. You can help users sift through your markers by adding filters to let them turn layers on and off. In this example, the script automatically creates a toggle option for each marker symbol and will only add a new layer to the toggle list if its marker-symbol is declared in the GeoJSON.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.js'></script>
  <link href='https://api.mapbox.com/mapbox.js/v3.0.1/mapbox.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding :0;
    }
    .map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>
<body>
<style>
.filter-ui {
  background: #fff;
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 100;
  padding: 10px;
  border-radius: 3px;
}

.filter-ui input {
  vertical-align: middle;
}
</style>
<nav id='filters' class='filter-ui'></nav>
<div id='map-toggle' class='map'></div>
<script>
L.mapbox.accessToken = '<your access token here>';

var mapToggle = L.mapbox.map('map-toggle')
  .setView([38.9, -77], 11)
  .addLayer(L.mapbox.tileLayer('mapbox.light'));

var filters = document.getElementById('filters');

var markers = L.mapbox.featureLayer().loadURL('/help/data/examples/dc-weekend-picks.geojson');

markers.on('ready', function(e) {
  var typesObj = {},
    types = [];
  var features = e.target._geojson.features;
  for (var i = 0; i < features.length; i++) {
    typesObj[features[i].properties['marker-symbol']] = true;
  }
  for (var key in typesObj) {
    if ({}.hasOwnProperty.call(typesObj, key)) {
      types.push(key);
    }
  }
  var checkboxes = [];
  for (var j = 0; j < types.length; j++) {
    var item = filters.appendChild(document.createElement('div'));
    var checkbox = item.appendChild(document.createElement('input'));
    var label = item.appendChild(document.createElement('label'));
    checkbox.type = 'checkbox';
    checkbox.id = types[j];
    checkbox.checked = true;
    label.innerHTML = types[j];
    label.setAttribute('for', types[j]);
    checkbox.addEventListener('change', update);
    checkboxes.push(checkbox);
  }

  function update() {
    var enabled = {};
    for (var k = 0; k < checkboxes.length; k++) {
      if (checkboxes[k].checked) enabled[checkboxes[k].id] = true;
    }
    markers.setFilter(function(feature) {
      return feature.properties['marker-symbol'] in enabled;
    });
  }
}).addTo(mapToggle);
mapToggle.scrollWheelZoom.disable();
</script>
</body>
</html>

More examples

For more ideas on how to filter or toggle your markers, check out these examples:

Next steps

Congratulations — you’re now a markers expert! You have the tools, code, and inspiration to add any markers you need to your map. If you’re looking for more ways to extend your Mapbox.js project, be sure to check out our Build a store locator tutorial.