Skip to content

Display Vector Tiles in Leaflet

Basic Map

Leaflet has no vector tile renderer of its own. The @maplibre/maplibre-gl-leaflet plugin adds one as a Leaflet layer, so the Maptoolkit vector style renders inside an ordinary Leaflet map and the marker on top is a normal L.marker:

const map = L.map("map").setView([47.310897, 12.805988], 12);

    L.maplibreGL({
      style: "https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=YOUR_API_KEY",
    }).addTo(map);

    L.marker([47.3249, 12.7967]).addTo(map).bindPopup("Zell am See");
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@5.6.1/dist/maplibre-gl.css" />
  <script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/maplibre-gl@5.6.1/dist/maplibre-gl.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@maplibre/maplibre-gl-leaflet@0.1.4/leaflet-maplibre-gl.js"></script>
  <style>
    html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
    #map { width: 100%; height: 100%; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const map = L.map("map").setView([47.310897, 12.805988], 12);

    L.maplibreGL({
      style: "https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=YOUR_API_KEY",
    }).addTo(map);

    L.marker([47.3249, 12.7967]).addTo(map).bindPopup("Zell am See");
  </script>
</body>
</html>

Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.

Use the Maptoolkit Connector. Create an html file of a Leaflet map that shows Maptoolkit vector tiles through the maplibre-gl-leaflet plugin, centered on Zell am See at zoom level 12, with a marker and popup on the town.

How it works

L.maplibreGL creates a MapLibre GL JS map inside a Leaflet layer and keeps its camera in step with Leaflet’s. MapLibre draws the vector tiles into a WebGL canvas, and Leaflet stays in charge of everything else: panning, zooming, markers, popups and controls. Code written for L.tileLayer keeps working, you only swap the basemap layer.

The script order matters. The plugin reads the global maplibregl when it loads, so maplibre-gl.js has to come before leaflet-maplibre-gl.js. In the wrong order the map stays grey and the console shows maplibre_gl.Map is not a constructor.

Use MapLibre GL JS 5 from a CDN. Version 6 ships only as an ES module, so there is no maplibre-gl.js file for it to load with a <script> tag, and the plugin needs that global.

The api_key travels in the style URL, and MapLibre reuses it for every tile request. The attribution comes from the style as well: the plugin copies © Maptoolkit © OSM into Leaflet’s attribution control, so there is no attribution option to set, unlike with raster tiles.

getMaplibreMap() on the layer returns the underlying MapLibre map. Use it for anything that belongs to the vector style itself, such as setLayoutProperty to hide a layer or addLayer for data drawn in WebGL.

Leaflet takes [latitude, longitude]. The MapLibre map behind the layer, including anything you call through getMaplibreMap(), takes [longitude, latitude].

Next steps

Vector tiles in Leaflet make sense when you want what raster tiles cannot give you: labels in the reader’s language, sharp rendering at any zoom and a style you can change in the browser. If none of that matters for your map, raster tiles in Leaflet are the lighter option, with no WebGL and no second library.

Leaflet cannot tilt or rotate the map, so 3D terrain and 3D buildings are out of reach this way. For those, use MapLibre GL JS directly with the same style URL.