We’ll see how to use SVG elements as icons for Leaflet markers. This will allow us to have all of the advantages of inline SVG, namely:
- Small size.
- Customizability via CSS styling.
The most powerful advantage will come with CSS styling. We’ll see how to easily change colors, or style the same SVG icons in different ways.
Setting up the SVG icon
For this tutorial, we’ll use a very simple SVG icon.
<svg width="100" height="100" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <path d="M0 0 L50 100 L100 0 Z" fill="##7A8BE7"></path> </svg>
This icon has a size of 100×100 pixels. We’ll scale it down to a more appropriate size of 24×40 pixels for a marker icon. To do so, we set the height
and width
attributes of the <svg>
. For the scaling to make effect, the viewBox
attribute must be set to the “original” bounds of the SVG element.
<svg width="24" height="40" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <path d="M0 0 L50 100 L100 0 Z" fill="##7A8BE7"></path> </svg>
Setting up a Leaflet map
We will setup a simple map as follows:
<!-- index.html --> <head> ... <link href="styles.css" rel="stylesheet" /> </head> <body> <div id="map"></div> <script src="script.js"></script> </body>
/* sytles.css */ #map { height: 400px; width: 400px; }
// script.js const map = L.map("map").setView([0, 0], 1); L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', }).addTo(map);
The corresponding map will look as shown below.
For a more detailed explanation to setup Leaflet, see their official quick start guide.
Creating a new Leaflet icon
Now, we’ll see how to use the SVG element of the first section as a Leaflet icon. While there’s an official tutorial on how to use custom icons, it’s inappropriate for our purposes because they use the Icon
class. This class is implemented using <img>
and it would embed the <svg>
element inside it. While this isn’t inherently bad, we would lose the capability of modifying the SVG icon directly using CSS.
For this reason, we’ll use the DivIcon class instead. This will preserve the <svg>
element as an inline HTML component which can be styled using CSS.
DivIcon represents a lightweight icon for markers that uses a simple
Leaflet docs<div>
element instead of an image.
To use the svg
element as an icon, we pass it to the html
property when creating a new DivIcon
.
const svgIcon = L.divIcon({ html: ` <svg width="24" height="40" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <path d="M0 0 L50 100 L100 0 Z" fill="#7A8BE7"></path> </svg>`, className: "", iconSize: [24, 40], iconAnchor: [12, 40], });
See that we’re also setting the iconSize
to the corresponding size of the SVG element. The iconAnchor
is the position of the “tip” of the icon, relative to the top-left corner. In our case, that’s the bottom-mid position of the icon. The className
property is set to an empty string to avoid Leaflet adding the new icon to the leaflet-div-icon
class. This would add both a border and a white background to the icon, which we don’t want.
Once defined, we can add a marker to the map using our previously defined svgIcon
.
L.marker([0, 0], { icon: svgIcon }).addTo(map);
The resulting map.
Customizing the SVG icon
While we’ve already managed to use an SVG as a marker icon, let’s take this one step further by styling it using CSS.
First, let’s define a new CSS rule associated to the svg-icon
class.
/* styles.css */ .svg-icon path { fill: crimson; }
This rule will change the fill color of all the <path>
elements that belong to a parent element of the svg-icon
class.
We will add this class to our SVG icon when defining it.
const svgIcon = L.divIcon({ html: ` <svg width="24" height="40" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <path d="M0 0 L50 100 L100 0 Z" fill="#7A8BE7"></path> </svg>`, className: "svg-icon", iconSize: [24, 40], iconAnchor: [12, 40], });
Now, when we add a new marker using svgIcon
, it will look like this on the map.
Leaflet markers with custom colors
As a final application, let’s give markers different colors while using the same icon.
First, we’ll create some new CSS rules.
.green path { fill: darkgreen; } .blue path { fill: navy; } .golden path { fill: gold; }
Next, let’s create some new markers, and save their references.
const greenMarker = L.marker([-50, 0], { icon: svgIcon }).addTo(map); const blueMarker = L.marker([50, 50], { icon: svgIcon }).addTo(map); const goldenMarker = L.marker([50, -50], { icon: svgIcon }).addTo(map);
Finally, we’ll add the corresponding CSS classes to the icon of each marker.
greenMarker._icon.classList.add("green"); blueMarker._icon.classList.add("blue"); goldenMarker._icon.classList.add("golden");
The resulting map.
Using inline SVG elements as icons for Leaflet markers, gives us a lot of flexibility when it comes to styling. We covered a few applications in this tutorial.
Working examples: here, codepen. For some reason the OSM tiles are not shown on Firefox, they work fine on Chrome.
For reference. With Leaflet 1.7.1:
I tested it on Leaflet 1.7.1 with no error messages. Check the example here.
Maybe you didn’t copy part of the code?
Hi
Very nice! How can I rotate the SVG (using the anchor as rotation point)?
You could take a look at the CSS transform rotate and transform origin properties.
Property ‘_icon’ does not exist on type ‘Marker<any>’.
Thanks for the great SVG tutorial!
As an avid Firefox user, the fix for the examples is that you need to add “https:” to the OSM tiles, http won’t work because Firefox has a strict no-mixed https/http policy: