Use Leaflet.VectorGrid with an uploaded vector tileset
Copy JavaScript and React examples for rendering uploaded Mappinest vector tiles with Leaflet.VectorGrid.
Overview
This guide shows the Leaflet-native path for uploaded vector tilesets. It uses Leaflet.VectorGrid after fetching the Mappinest TileJSON document.
If your tileset starts as an MBTiles or PMTiles file, upload it through the console first. See Upload Data for the full upload workflow, then return with the tileset Id and API key from API Keys & Access.
Start with Add vector tileset when you only need to render the layer on top of a Mappinest map style. Choose this VectorGrid path when you need Leaflet layer events, popups, or plugin workflows around the uploaded vector tileset.
The example uses mappinest.COUNTIES as the sample uploaded vector tileset. It fetches TileJSON first, reads the returned tile template and source layer metadata, then passes those values to Leaflet.VectorGrid.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mappinest vector TileJSON with Leaflet.VectorGrid</title>
<link href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" rel="stylesheet" />
<link href="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.css" rel="stylesheet" />
<style>
body { margin: 0; }
#map { height: 100vh; width: 100vw; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/maplibre-gl@5/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.1.3/leaflet-maplibre-gl.js"></script>
<script src="https://unpkg.com/leaflet.vectorgrid@1.3.0/dist/Leaflet.VectorGrid.bundled.min.js"></script>
<script>
const apiKey = 'YOUR_MAPPINEST_KEY';
async function initMap() {
// Fetch TileJSON first, then pass the returned tile URL and layer metadata to Leaflet.VectorGrid.
const tilejson = await fetch(
`https://api.mappinest.com/v1/tiles/mappinest.COUNTIES.json?key=${apiKey}`
).then((response) => response.json());
const tilesUrl = tilejson.tiles?.[0];
// Choose the TileJSON vector_layers[].id for the layer you want Leaflet.VectorGrid to render.
const sourceLayer = tilejson.vector_layers?.[0]?.id || 'COUNTIES';
if (!tilesUrl) {
throw new Error('TileJSON did not return a tile URL.');
}
const map = L.map('map').setView([39.8283, -98.5795], 4);
L.maplibreGL({
style: `https://api.mappinest.com/v1/styles/light/style.json?key=${apiKey}`,
interactive: false
}).addTo(map);
// Leaflet.VectorGrid renders vector tiles from that returned tile template.
L.vectorGrid.protobuf(tilesUrl, {
interactive: true,
vectorTileLayerStyles: {
[sourceLayer]: {
color: '#2563eb',
weight: 1,
fillColor: '#2563eb',
fillOpacity: 0.28
}
}
}).addTo(map);
}
initMap();
</script>
</body>
</html>import { useEffect, useRef } from 'react';
import L from 'leaflet';
import '@maplibre/maplibre-gl-leaflet';
import 'leaflet.vectorgrid';
import 'leaflet/dist/leaflet.css';
import 'maplibre-gl/dist/maplibre-gl.css';
const apiKey = 'YOUR_MAPPINEST_KEY';
export default function MappinestLeafletVectorTilesMap() {
const containerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<L.Map | null>(null);
useEffect(() => {
if (!containerRef.current || mapRef.current) return;
let cancelled = false;
async function initMap() {
// Fetch TileJSON first, then pass the returned tile URL and layer metadata to Leaflet.VectorGrid.
const tilejson = await fetch(
`https://api.mappinest.com/v1/tiles/mappinest.COUNTIES.json?key=${apiKey}`
).then((response) => response.json());
if (cancelled || !containerRef.current) return;
const tilesUrl = tilejson.tiles?.[0];
// Choose the TileJSON vector_layers[].id for the layer you want Leaflet.VectorGrid to render.
const sourceLayer = tilejson.vector_layers?.[0]?.id || 'COUNTIES';
if (!tilesUrl) {
throw new Error('TileJSON did not return a tile URL.');
}
const map = L.map(containerRef.current).setView([39.8283, -98.5795], 4);
mapRef.current = map;
(L as any).maplibreGL({
style: `https://api.mappinest.com/v1/styles/light/style.json?key=${apiKey}`,
interactive: false
}).addTo(map);
// Leaflet.VectorGrid renders vector tiles from that returned tile template.
(L as any).vectorGrid.protobuf(tilesUrl, {
interactive: true,
vectorTileLayerStyles: {
[sourceLayer]: {
color: '#2563eb',
weight: 1,
fillColor: '#2563eb',
fillOpacity: 0.28
}
}
}).addTo(map);
}
void initMap();
return () => {
cancelled = true;
mapRef.current?.remove();
mapRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ height: 420, width: '100%' }} />;
}TileJSON URL pattern
Fetch TileJSON first. Leaflet.VectorGrid uses the direct tile URL from the returned tiles array and the layer id from vector_layers[].id.
Get your free API key in API Keys & Access, then replace YOUR_KEY in the example.
When to use this path
Common errors
What to read next
Last updated: June 24, 2026