All integrations MapLibre Leaflet OpenLayers React WordPress API docs
Leaflet draws raster image tiles out of the box. ExpressMaps serves vector tiles, which stay crisp on high-density screens and at every zoom level, so you render them inside Leaflet with the official maplibre-gl-leaflet plugin. It adds one Leaflet layer backed by MapLibre GL JS. Everything else, from markers and popups to GeoJSON and third-party Leaflet plugins, keeps working as before.
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css">
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.0.22/leaflet-maplibre-gl.js"></script>
Where you would normally call L.tileLayer(...), call L.maplibreGL with a style URL instead. Replace YOUR_API_KEY with a key from the console.
<div id="map" style="width: 100%; height: 400px;"></div>
<script>
var map = L.map("map").setView([51.5072, -0.1276], 12);
L.maplibreGL({
style: "https://tiles.expressmaps.com/styles/standard.json?key=YOUR_API_KEY"
}).addTo(map);
</script>
These are ordinary Leaflet layers drawn on top of the map, so existing code needs no changes. Leaflet uses [lat, lng] order.
L.marker([51.5072, -0.1276])
.bindPopup("<b>Our office</b><br>Open 9 to 5")
.addTo(map);
fetch("/stores.geojson")
.then(function (r) { return r.json(); })
.then(function (data) {
L.geoJSON(data, {
onEachFeature: function (f, layer) { layer.bindPopup(f.properties.name); }
}).addTo(map);
});
Create one layer per style and hand them to Leaflet's layers control. This is what the live map above does. See all ten styles.
var key = "YOUR_API_KEY";
function expressmaps(style) {
return L.maplibreGL({ style: "https://tiles.expressmaps.com/styles/" + style + ".json?key=" + key });
}
var styles = {
"Standard": expressmaps("standard"),
"Subtle": expressmaps("subtle"),
"Darklands": expressmaps("darklands")
};
styles["Standard"].addTo(map);
L.control.layers(styles).addTo(map);
npm install leaflet maplibre-gl @maplibre/maplibre-gl-leaflet import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "maplibre-gl/dist/maplibre-gl.css";
import "@maplibre/maplibre-gl-leaflet";
const map = L.map("map").setView([51.5072, -0.1276], 12);
L.maplibreGL({ style: "https://tiles.expressmaps.com/styles/standard.json?key=YOUR_API_KEY" }).addTo(map);
If your map uses L.tileLayer("https://.../{z}/{x}/{y}.png") today, remove that line and add the L.maplibreGL layer above. We do not serve raster PNG tiles; vector tiles are smaller to download, sharp on retina screens and rotate labels correctly. Attribution comes from the style, so you can drop any hand-written OpenStreetMap credit.