React components for Leaflet maps
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
React components for Leaflet maps using React's declarative component model with full TypeScript support.
| Property | Value |
|---|---|
| Package | react-leaflet |
| Version | 5.0.0 |
| Type | npm |
| Language | TypeScript |
| Installation | npm install react-leaflet leaflet |
| Peer Dependencies | leaflet ^1.9.0, react ^19.0.0, react-dom ^19.0.0 |
| Bundle Size | ~15KB minified + gzipped |
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
function MyMap() {
return (
<MapContainer center={[51.505, -0.09]} zoom={13} style={{ height: "400px" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
<Marker position={[51.505, -0.09]}>
<Popup>A sample popup</Popup>
</Marker>
</MapContainer>
);
}📖 See Quick Start Guide for detailed setup instructions
eventHandlers prop or custom hooksMapContainer (required root)
├── TileLayer (base map)
├── Markers & Popups (point features)
├── Vector Shapes (circles, polygons, lines)
├── Layer Groups (organize layers)
├── Controls (UI elements)
└── Media Overlays (images, video, SVG)| Component | Purpose | Key Props |
|---|---|---|
MapContainer | Root map container | center, zoom, style |
TileLayer | Base map tiles | url, attribution |
Marker | Point marker | position, icon |
Popup | Info popup | children, position |
Tooltip | Hover tooltip | children, permanent |
| Hook | Purpose |
|---|---|
useMap() | Access map instance |
useMapEvent(type, handler) | Single event handler |
useMapEvents(handlers) | Multiple event handlers |
| Component | Description | Radius Unit |
|---|---|---|
Circle | Circle with geographic radius | Meters |
CircleMarker | Circle with pixel radius | Pixels |
Polyline | Multi-segment line | - |
Polygon | Filled polygon | - |
Rectangle | Rectangle from bounds | - |
| Component | Purpose |
|---|---|
LayersControl | Switch between layers |
ZoomControl | Zoom buttons |
ScaleControl | Map scale display |
AttributionControl | Attribution text |
// Core components
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
// Hooks
import { useMap, useMapEvent, useMapEvents } from "react-leaflet";
// Vector shapes
import { Circle, CircleMarker, Polyline, Polygon, Rectangle } from "react-leaflet";
// Layer groups
import { LayerGroup, FeatureGroup, GeoJSON, Pane } from "react-leaflet";
// Controls
import { LayersControl, ZoomControl, ScaleControl, AttributionControl } from "react-leaflet";
// Media overlays
import { ImageOverlay, SVGOverlay, VideoOverlay } from "react-leaflet";
// Core APIs (advanced)
import { useLeafletContext, createLayerComponent } from "@react-leaflet/core";// Position types
type LatLngExpression =
| LatLng
| [number, number]
| { lat: number; lng: number };
type LatLngBoundsExpression =
| LatLngBounds
| [LatLngExpression, LatLngExpression];
// Control position
type ControlPosition = 'topleft' | 'topright' | 'bottomleft' | 'bottomright';
// Path styling
interface PathOptions {
stroke?: boolean;
color?: string;
weight?: number;
opacity?: number;
fill?: boolean;
fillColor?: string;
fillOpacity?: number;
}npm install react-leaflet leaflet
npm install -D @types/leaflet # TypeScriptimport "leaflet/dist/leaflet.css";import L from "leaflet";
import icon from "leaflet/dist/images/marker-icon.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
});
L.Marker.prototype.options.icon = DefaultIcon;<MapContainer style={{ height: "400px", width: "100%" }}>function ChangeView({ center, zoom }) {
const map = useMap();
map.setView(center, zoom);
return null;
}
<MapContainer center={center} zoom={zoom}>
<ChangeView center={center} zoom={zoom} />
<TileLayer url="..." />
</MapContainer>const mapRef = useRef<Map | null>(null);
<MapContainer ref={mapRef} center={[51.505, -0.09]} zoom={13}>
{/* ... */}
</MapContainer>function MapEvents() {
useMapEvents({
click: (e) => console.log('Clicked at:', e.latlng),
zoomend: () => console.log('Zoom changed'),
});
return null;
}⚠️ MapContainer props are immutable - Use refs/hooks for dynamic updates
⚠️ Leaflet CSS required - Must import leaflet/dist/leaflet.css
⚠️ Components must be inside MapContainer - To access map context
⚠️ Coordinate order - Leaflet uses [lat, lng], GeoJSON uses [lng, lat]
⚠️ SSR - Use dynamic imports for Next.js/server-side rendering
⚠️ Performance - Use preferCanvas={true} for many vector shapes
| Issue | Solution |
|---|---|
| Map not displaying | Import Leaflet CSS, set explicit height |
| Markers not appearing | Fix default icon paths (see setup) |
| Events not firing | Ensure interactive={true}, check event handlers |
| Performance issues | Use preferCanvas={true}, implement clustering |
| TypeScript errors | Install @types/leaflet |
| SSR errors | Use dynamic imports, disable SSR for MapContainer |
Choose Circle vs CircleMarker:
Choose LayerGroup vs FeatureGroup:
Choose TileLayer vs ImageOverlay:
Choose Marker vs CircleMarker: