Use Maptoolkit Tiles with React Leaflet
react-leaflet wraps Leaflet in React components. Maptoolkit
raster tiles go into its TileLayer, and everything else is standard react-leaflet.
Install
npm install leaflet react-leafletreact-leaflet 5 requires React 19. On React 18, install version 4 instead with
npm install react-leaflet@4; the code on this page works with both.
The component
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
const KEY = import.meta.env.VITE_MAPTOOLKIT_KEY;
export default function LeafletMap() {
return (
<MapContainer center={[47.2692, 11.4041]} zoom={13} style={{ height: "400px" }}>
<TileLayer
url={`https://rtc-cdn.maptoolkit.net/rtc/maptoolkit-maptoolkit.summer/{z}/{x}/{y}{r}.png?api_key=${KEY}`}
maxZoom={18}
attribution='© <a href="https://www.maptoolkit.com">Maptoolkit</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
/>
<Marker position={[47.2692, 11.4041]}>
<Popup>Innsbruck</Popup>
</Marker>
</MapContainer>
);
}MapContainerneeds a height. Without one it is zero pixels tall and nothing renders, with no error.- The stylesheet import is required. Without
leaflet/dist/leaflet.css, tiles render as a scattered mosaic across the page. {r}is Leaflet’s retina placeholder. It becomes@2xon high-density screens and an empty string elsewhere, and Maptoolkit serves both tile sizes from the same URL.- The
attributionprop is required. Raster tiles carry no credit of their own, so without it the map shows no attribution, which the license does not allow.
The style id in the URL follows maptoolkit-maptoolkit.<variant>. The seven variants are
listed under Standard Map Styles.
The marker icon is missing in production
A Marker that shows correctly in the development server can turn into a broken image
after npm run build. Leaflet finds its default icon images by reading a path out of its own
stylesheet at runtime, and the bundler renames and moves those files, so the path points
nowhere.
Import the images through the bundler and hand Leaflet the resulting URLs. Put this in its own module and import it once, before any map renders:
// leaflet-icons.js
import L from "leaflet";
import iconUrl from "leaflet/dist/images/marker-icon.png";
import iconRetinaUrl from "leaflet/dist/images/marker-icon-2x.png";
import shadowUrl from "leaflet/dist/images/marker-shadow.png";
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({ iconUrl, iconRetinaUrl, shadowUrl });import "./leaflet-icons";Both lines are needed. Without the delete, Leaflet still puts its detected path in front of
the URLs you pass, and the icon then breaks in the development server.
Changing the map after it mounts
MapContainer reads center and zoom once, when it mounts. Changing them later does
nothing. To move the map, get the Leaflet map instance with useMap() inside a child
component and call it from an effect:
import { useEffect } from "react";
import { useMap } from "react-leaflet";
function FlyTo({ position }) {
const map = useMap();
useEffect(() => {
map.flyTo(position, 13);
}, [map, position]);
return null;
}<MapContainer center={[47.2692, 11.4041]} zoom={13} style={{ height: "400px" }}>
<TileLayer url={tileUrl} attribution={attribution} />
<FlyTo position={selectedCity} />
</MapContainer>useMap() only works inside MapContainer, so FlyTo has to be one of its children.
react-leaflet creates and removes the Leaflet map for you, so there is no cleanup to write and no guard against React’s StrictMode double mount. That is different from using Leaflet or Maps JS directly, where both are your job.
Where to put the API key
The example reads the key from VITE_MAPTOOLKIT_KEY, the Vite convention. Other build tools
use a different prefix, but all of them inline the value into the JavaScript the browser
downloads. A map key is always visible in the browser, so restrict it to your domains in your
account.
Next steps
With the map mounted, the next step is usually your own data on top. react-leaflet has
GeoJSON, Polyline and Polygon components for that, and the
Routing API with Leaflet example shows a route drawn from
API data.
If your app needs a different basemap per context, for example Winter in the season and
Hiking in summer, the raster tiles Leaflet example builds a
style switcher, and each style is one more TileLayer inside react-leaflet’s LayersControl.