Custom Icon for marker with react-leaflet does not show up

4.3k Views Asked by At

I'm trying to use a custom icon with markers with react-leaflet

Following the indications found here: https://leafletjs.com/examples/custom-icons/ and here: https://roblahoda.com/blog/leaflet-react-custom-icons/

I added these lines of code:

import Leaflet from 'leaflet'
import "leaflet/dist/leaflet.css"

import React from 'react'
import {
  TileLayer,
  LayersControl,
  LayerGroup,
  useMap,
  useMapEvents,
  GeoJSON,
  Marker,
  Popup,
} from 'react-leaflet'

export const newicon = new Leaflet.Icon({
  iconUrl: ("../../..assets/marker.svg"),
  iconAnchor: [5, 55],
  popupAnchor: [10, -44],
  iconSize: [25, 55],
})

And for the Marker I specified the newicon :

    <Marker position={getMarkerPosition(state_name)} icon={newicon}>

(base) raphy@pc:~/Raphy-Template/src/assets$ ls -lah
    total 56K
    -rw-rw-r--  1 raphy raphy 5.0K Jan 31 11:40 marker.png

But the new icon is not properly rendered:

enter image description here

Update 1)

Using require:

export const newicon = new Leaflet.Icon({
  iconUrl: require("../../../assets/marker.svg"),
  iconAnchor: [5, 55],
  popupAnchor: [10, -44],
  iconSize: [25, 55],
})

I get this error: Module not found: Error: Can't resolve '../../../assets/marker.svg'

With import instead if require I do not get any error, but still the icon doesn't show up:

export const newicon = new Leaflet.Icon({
  // @ts-ignore
  iconUrl: import("../../../assets/svg/push_pin_black_36dp.svg"),

  iconAnchor: [5, 55],
  popupAnchor: [10, -44],
  iconSize: [25, 55],
})


(base) raphy@pc:~/Raphy-Template/dist/assets/svg$ ls -lah
    -rw-rw-r-- 1 raphy raphy  390 Jan 31 19:05 
push_pin_black_36dp.svg
    (base) raphy@pc:~/Raphy-Template/dist/assets/svg$ 

Other info:

I've put the code inside this CodeSandbox repo: https://codesandbox.io/s/damp-tdd-i917u?file=/src/App.js

"react": "^17.0.2"
"react-leaflet": "^3.2.5"
node: v16.13.0
O.S.: Ubuntu 20.04 Desktop

How to make the custom icon appear?

1

There are 1 best solutions below

5
ghybs On

Remember that your React app project is built and moved to another place in your file system. In particular, assets like your icon image / SVG may not be bundled, or placed in a different position relatively to your script.

In the blog about React Leaflet with custom icons you refer to, notice how the path to the image assets is specified: it uses require("some/path"), which webpack understands as a directive to bundle the specified asset and provide the resulting built path.

So in your case, you would simply do:

export const newicon = new Leaflet.Icon({
  iconUrl: require("../../../assets/marker.svg") // require the path to the asset
})

That being said, it looks like some build engine configurations convert the require('path/to/some/svg') as a React component-like object (much probably to be able to use SVG as if it were a React component, see https://create-react-app.dev/docs/adding-images-fonts-and-files/#adding-svgs), and provide the built URL in the Url property of such object:

export const newicon = new Leaflet.Icon({
  iconUrl: require("../../../assets/marker.svg").Url // require the path to the asset
})

Another option is to use a more standard import at the beginning of the file. In this case, with the same build engine configuration as provided in your CodeSandbox, it just gives the resulting URL as expected (which is actually an inlined Base64 data):

import iconUrl from "./svg/push_pin_black_36dp.svg";

export const newicon = new Leaflet.Icon({
  iconUrl
});

Demo: https://codesandbox.io/s/quiet-shape-6ise9?file=/src/App.js