React Leaflet Marker Cluster
react-leaflet-cluster is a plugin that integrates Leaflet.markercluster functionality into React-Leaflet applications. It provides a `MarkerClusterGroup` component for easily creating animated marker clusters on maps. The current stable version is 4.1.3, with recent updates (v4.1.0) focusing on performance improvements for layer additions. The library maintains an active release cadence, frequently updating to support the latest versions of its core peer dependencies, including React 19, React-Leaflet 5, and Leaflet 1.9.x. Key differentiators include robust TypeScript support, explicit compatibility with Next.js by requiring manual CSS imports, and a strong focus on keeping up with its ecosystem's major version bumps, making it a reliable choice for modern React mapping projects requiring marker clustering capabilities.
Common errors
-
TypeError: Cannot read properties of undefined (reading '_getIconUrl')
cause Leaflet's default marker icons are not correctly configured after v3.1.0, typically due to a missing or misconfigured `L.Icon.Default.mergeOptions` call.fixImplement the manual icon configuration as shown in the warnings section for versions >=3.1.0, ensuring Leaflet can find the default marker assets. -
MarkerClusterGroup component renders unstyled or incorrectly styled clusters (e.g., plain squares instead of styled circles)
cause The required CSS files for MarkerClusterGroup are not imported, which is necessary since v3.0.0.fixAdd the necessary CSS imports to your entry file or map component: `import 'react-leaflet-cluster/dist/assets/MarkerCluster.css'; import 'react-leaflet-cluster/dist/assets/MarkerCluster.Default.css';` -
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
cause This general React error can occur in older `react-leaflet-cluster` versions (pre-v2.1.0) due to a Hooks order problem or mismatched React/React-Leaflet versions.fixUpgrade to `react-leaflet-cluster` v2.1.0 or newer and ensure your `react` and `react-leaflet` peer dependencies are compatible with the installed version.
Warnings
- breaking Version 4.0.0 introduced significant peer dependency updates. Projects must upgrade to React 19, React-Leaflet 5, Leaflet 1.9.0, and @react-leaflet/core 3.0.0 or newer.
- breaking Since v3.0.0, CSS files for MarkerClusterGroup are no longer automatically imported. You must manually import them to ensure proper styling, especially to avoid issues in environments like Next.js.
- breaking As of v3.1.0, the package no longer automatically configures Leaflet's default marker icons. If you use default Leaflet markers, their icons will appear broken without manual configuration.
- gotcha Version 4.1.0 introduced a performance optimization that buffers `addLayer()` calls and flushes them in a microtask. While an improvement, developers should be aware of this asynchronous behavior if relying on immediate layer state updates within the same event loop tick.
Install
-
npm install react-leaflet-cluster -
yarn add react-leaflet-cluster -
pnpm add react-leaflet-cluster
Imports
- MarkerClusterGroup
import { MarkerClusterGroup } from 'react-leaflet-cluster'import MarkerClusterGroup from 'react-leaflet-cluster'
- CSS Styles
require('react-leaflet-cluster/dist/assets/MarkerCluster.css')import 'react-leaflet-cluster/dist/assets/MarkerCluster.css' import 'react-leaflet-cluster/dist/assets/MarkerCluster.Default.css'
- L (Leaflet global)
const L = require('leaflet')import L from 'leaflet'
Quickstart
import React from 'react';
import { MapContainer, TileLayer, Marker } from 'react-leaflet';
import MarkerClusterGroup from 'react-leaflet-cluster';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'react-leaflet-cluster/dist/assets/MarkerCluster.css';
import 'react-leaflet-cluster/dist/assets/MarkerCluster.Default.css';
// Configure default marker icons (required since v3.1.0)
delete (L.Icon.Default as any).prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png'
});
const position = [51.505, -0.09]; // London coordinates
function App() {
// Generate a large number of random markers for clustering demonstration
const markers = Array.from({ length: 500 }, (_, i) => ({
position: [
position[0] + (Math.random() - 0.5) * 0.1,
position[1] + (Math.random() - 0.5) * 0.2
],
key: `marker-${i}`
}));
return (
<MapContainer center={position} zoom={10} style={{ height: '100vh', width: '100%' }}>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerClusterGroup chunkedLoading>
{markers.map((marker) => (
<Marker key={marker.key} position={marker.position} />
))}
</MarkerClusterGroup>
</MapContainer>
);
}
export default App;