Issue
I'm using leaflet v1.7.1 and react-leaflet v3.0.5 in my React project.
When I try out the setup example in React Router's "Setup" documentation page, the marker icon becomes a broken image as circled in red below:
From the React Router's documentation, this is what the marker should look like:
Upon inspection, the src
attribute of the <img>
tag that holds the marker image should be /[email protected]/dist/images/marker-icon-2x.png
. However, upon inspection, my <img>
's src
attribute turns out to be gibberish-looking:
Replication
I've created a new sandbox which contains my code:
Alternatively, follow these steps to replicate the issue:
npx create-react-app leaflet-test
cd leaflet-test/
npm i leaflet react-leaflet
Open the project in code editor. Go to
App.js
and use the following code:import React from "react"; import "./App.css"; import "leaflet/dist/leaflet.css"; import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; const styles = { mapRoot: { height: 400, }, }; export default function App() { return ( <MapContainer style={styles.mapRoot} center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false} > <TileLayer attribution='© <a href=";>OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap/{z}/{x}/{y}.png" /> <Marker position={[51.505, -0.09]}> <Popup> A pretty CSS3 popup. <br /> Easily customizable. </Popup> </Marker> </MapContainer> ); }
npm start
I'm not sure whether I've set-up Leaflet wrongly in React or it's a bug from Leaflet or React Leaflet. Thanks in advance!
Issue
I'm using leaflet v1.7.1 and react-leaflet v3.0.5 in my React project.
When I try out the setup example in React Router's "Setup" documentation page, the marker icon becomes a broken image as circled in red below:
From the React Router's documentation, this is what the marker should look like:
Upon inspection, the src
attribute of the <img>
tag that holds the marker image should be https://unpkg.com/[email protected]/dist/images/marker-icon-2x.png
. However, upon inspection, my <img>
's src
attribute turns out to be gibberish-looking:
Replication
I've created a new sandbox which contains my code:
Alternatively, follow these steps to replicate the issue:
npx create-react-app leaflet-test
cd leaflet-test/
npm i leaflet react-leaflet
Open the project in code editor. Go to
App.js
and use the following code:import React from "react"; import "./App.css"; import "leaflet/dist/leaflet.css"; import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; const styles = { mapRoot: { height: 400, }, }; export default function App() { return ( <MapContainer style={styles.mapRoot} center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false} > <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <Marker position={[51.505, -0.09]}> <Popup> A pretty CSS3 popup. <br /> Easily customizable. </Popup> </Marker> </MapContainer> ); }
npm start
I'm not sure whether I've set-up Leaflet wrongly in React or it's a bug from Leaflet or React Leaflet. Thanks in advance!
Share Improve this question edited Feb 23, 2021 at 8:30 AnsonH asked Jan 17, 2021 at 8:05 AnsonHAnsonH 3,2662 gold badges22 silver badges43 bronze badges 3- 1 Maybe this thread will help you, good news is that its not your fault and it appears to be a common issue github.com/PaulLeCam/react-leaflet/issues/453 – FoundingBox Commented Jan 17, 2021 at 8:58
- Thank you so much :D I've found a fix from that issue thread. – AnsonH Commented Jan 17, 2021 at 9:02
- No problem, happy you found the solution :) – FoundingBox Commented Jan 17, 2021 at 9:03
3 Answers
Reset to default 9I faced Same Issues but found out this solution lately, all we need to do is pass an icon prop to the Marker component.
import marker from '../../Assets/icons/Location.svg';
import { Icon } from 'leaflet'
const myIcon = new Icon({
iconUrl: marker,
iconSize: [32,32]
})
<MapContainer center={value} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={value} icon={myIcon}>
<Popup>
Location :{data}
</Popup>
</Marker>
</MapContainer>
Check My Solution on CodeSandBox!
Thanks to FoundingBox's comment, it turns out that this is a bug of React Leaflet.
There is already a GitHub issue thread regarding this bug and this comment suggested the following solution:
OK. It turns out that the problem was caused by including the leaflet CSS in the component's imports.
I've now just included a link to the CDN hosted leaflet.css file and it's working OK, but it would be good if this could be patched to work with create-react-app webpack config.
In other words, here's the step by step guide:
Remove
import "leaflet/dist/leaflet.css";
fromApp.js
. Do NOT import the Leaflet CSS from the node modules in any JS files.Go to
public/index.html
and include the CDN hosted leaflet.css by pasting the following code in the<head>
section of the HTML file:<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
(Note: This link uses v1.7.1 of Leaflet. Visit Leaflet's documentation to find the code of linking the latest version of Leaflet)
For reference, this is due to webpack rewriting URL's in CSS, whereas Leaflet uses it to detect the paths to its icon images.
See the details in Leaflet issue #4968.
When using Leaflet through a CDN, the Leaflet CSS is not fiddled with, so it works correctly.
You can still use it through webpack, but you should either use only custom icons, or explicitly tell Leaflet where to find the images for its default icon:
import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});
I also made specifically a plugin for this case: leaflet-defaulticon-compatibility
Retrieve all Leaflet Default Icon options from CSS, in particular all icon images URL's, to improve compatibility with bundlers and frameworks that modify URL's in CSS.
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; // Re-uses images from ~leaflet package
import * as L from 'leaflet';
import 'leaflet-defaulticon-compatibility';