Skip to content

SVG nodes targeting

All IDs and classes of every SVG elements are prefixed with a unique string to avoid collisions. If you need this prefix, you can extract it like so:

import imageSrc, { prefix: imagePrefix } from "@/image.svg";

This works with any import method.

One of the purposes of this is targeting SVG elements in scripts or styles.

The demo below changes element’s colors when user clicks on it. Each element has its own color map. This is implemented via accessing by a class name.

Rendered demo
Demo's source code
src
assets
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 256 86" style="enable-background:new 0 0 256 86;" xml:space="preserve" width="100%" height="100%">
<g>
<g>
<rect class="left-element" x="8.9" y="6.6" width="114.8" height="72.8" fill="#d7bde2" />
<g>
<g>
<path d="M19.6,43.9c0-1.3,1-2,2.1-2c0.6,0,1.1,0.3,1.4,0.6l-0.3,0.4c-0.3-0.3-0.6-0.4-1.1-0.4c-0.9,0-1.5,0.6-1.5,1.5
c0,0.9,0.6,1.5,1.5,1.5c0.5,0,0.9-0.2,1.2-0.5l0.3,0.4c-0.4,0.4-1,0.6-1.5,0.6C20.5,45.9,19.6,45.2,19.6,43.9z"/>
<path d="M25.6,44.5v-3.8h-1.4v-0.5h2v4.4c0,0.6,0.3,0.8,0.8,0.8c0.2,0,0.5-0.1,0.7-0.2l0.2,0.5c-0.4,0.2-0.6,0.2-1,0.2
C26.1,45.9,25.6,45.4,25.6,44.5z"/>
<path d="M29.1,44.8c0-0.9,0.8-1.3,2.8-1.4c0-0.5-0.3-1-1-1c-0.5,0-1,0.2-1.3,0.5l-0.3-0.4c0.4-0.3,1-0.6,1.7-0.6
c1.1,0,1.6,0.6,1.6,1.6v2.4H32l-0.1-0.5h0c-0.4,0.3-1,0.6-1.5,0.6C29.7,45.9,29.1,45.5,29.1,44.8z M31.9,44.8v-1
c-1.6,0.1-2.1,0.5-2.1,1c0,0.4,0.4,0.6,0.8,0.6C31,45.4,31.4,45.2,31.9,44.8z"/>
<path d="M33.8,45.3l0.3-0.4c0.4,0.3,1,0.5,1.7,0.5c0.6,0,1-0.3,1-0.6c0-0.3-0.2-0.5-1.2-0.7c-1-0.2-1.5-0.5-1.5-1.1
c0-0.6,0.5-1.1,1.6-1.1c0.6,0,1.2,0.2,1.6,0.5l-0.3,0.4c-0.4-0.2-0.8-0.4-1.3-0.4c-0.6,0-0.9,0.3-0.9,0.6c0,0.3,0.3,0.5,1.1,0.6
c1.3,0.3,1.6,0.6,1.6,1.2c0,0.6-0.6,1.1-1.7,1.1C34.9,45.9,34.2,45.6,33.8,45.3z"/>
<path d="M38.5,45.3l0.3-0.4c0.4,0.3,1,0.5,1.7,0.5c0.6,0,1-0.3,1-0.6c0-0.3-0.2-0.5-1.2-0.7c-1-0.2-1.5-0.5-1.5-1.1
c0-0.6,0.5-1.1,1.6-1.1c0.6,0,1.2,0.2,1.6,0.5l-0.3,0.4c-0.4-0.2-0.8-0.4-1.3-0.4c-0.6,0-0.9,0.3-0.9,0.6c0,0.3,0.3,0.5,1.1,0.6
c1.3,0.3,1.6,0.6,1.6,1.2c0,0.6-0.6,1.1-1.7,1.1C39.7,45.9,39,45.6,38.5,45.3z"/>
<path d="M43.4,42.1h3.4v0.5h-3.4V42.1z M43.4,43.8h3.4v0.5h-3.4V43.8z"/>
<path d="M48.5,41.2l0-0.9h0.9l0,0.9L49.2,43h-0.4L48.5,41.2z M50.3,41.2l0-0.9h0.9l0,0.9L51,43h-0.4L50.3,41.2z"/>
<path d="M54.2,44.5v-3.8h-1.4v-0.5h2v4.4c0,0.6,0.3,0.8,0.8,0.8c0.2,0,0.5-0.1,0.7-0.2l0.2,0.5c-0.4,0.2-0.6,0.2-1,0.2
C54.6,45.9,54.2,45.4,54.2,44.5z"/>
<path d="M57.5,43.9c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4H58v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C58.4,45.9,57.5,45.2,57.5,43.9z"/>
<path d="M62.6,42l1.1,0h2.2v0.5h-3.4V42z M63.7,41.6c0-0.9,0.5-1.6,1.6-1.6c0.4,0,0.7,0.1,1.1,0.2l-0.2,0.5
c-0.3-0.1-0.6-0.2-0.9-0.2c-0.7,0-1,0.4-1,1v4.2h-0.6V41.6z"/>
<path d="M68.1,44.3v-1.8H67V42l1.1,0l0.1-1.2h0.5V42h1.9v0.5h-1.9v1.8c0,0.7,0.2,1,1,1c0.4,0,0.6-0.1,0.9-0.2l0.1,0.5
c-0.3,0.1-0.7,0.2-1.2,0.2C68.5,45.9,68.1,45.3,68.1,44.3z"/>
<path d="M71.9,43h3.4v0.5h-3.4V43z"/>
<path d="M76.5,43.9c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4H77v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C77.5,45.9,76.5,45.2,76.5,43.9z"/>
<path d="M82.7,44.5v-3.8h-1.4v-0.5h2v4.4c0,0.6,0.3,0.8,0.8,0.8c0.2,0,0.5-0.1,0.7-0.2l0.2,0.5c-0.4,0.2-0.6,0.2-1,0.2
C83.2,45.9,82.7,45.4,82.7,44.5z"/>
<path d="M86.1,43.9c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4h-3.3v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C87,45.9,86.1,45.2,86.1,43.9z"/>
<path d="M90.7,42h0.5l0.1,0.5h0c0.2-0.4,0.4-0.6,0.9-0.6c0.4,0,0.6,0.2,0.7,0.7c0.2-0.4,0.5-0.7,0.9-0.7c0.5,0,0.9,0.4,0.9,1.2
v2.8H94v-2.7c0-0.4-0.1-0.7-0.4-0.7c-0.3,0-0.4,0.2-0.6,0.6v2.8h-0.6v-2.7c0-0.4-0.1-0.7-0.4-0.7c-0.3,0-0.4,0.2-0.6,0.6v2.8
h-0.6V42z"/>
<path d="M95.6,43.9c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4H96v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C96.5,45.9,95.6,45.2,95.6,43.9z"/>
<path d="M100.5,42h0.5l0.1,0.6h0c0.4-0.4,0.8-0.7,1.4-0.7c0.9,0,1.3,0.5,1.3,1.6v2.4h-0.7v-2.3c0-0.7-0.3-1.1-0.9-1.1
c-0.5,0-0.8,0.2-1.2,0.7v2.7h-0.7V42z"/>
<path d="M106.2,44.3v-1.8h-1.1V42l1.1,0l0.1-1.2h0.5V42h1.9v0.5h-1.9v1.8c0,0.7,0.2,1,1,1c0.4,0,0.6-0.1,0.9-0.2l0.1,0.5
c-0.3,0.1-0.7,0.2-1.2,0.2C106.5,45.9,106.2,45.3,106.2,44.3z"/>
<path d="M110.3,41.2l0-0.9h0.9l0,0.9L111,43h-0.4L110.3,41.2z M112.2,41.2l0-0.9h0.9l0,0.9l-0.2,1.8h-0.4L112.2,41.2z"/>
</g>
</g>
</g>
<g>
<rect class="right-element" x="132.3" y="6.6" width="114.8" height="72.8" fill="#85c1e9" />
<g>
<g>
<path d="M140.4,43c0-1.3,1-2,2.1-2c0.6,0,1.1,0.3,1.4,0.6l-0.3,0.4c-0.3-0.3-0.6-0.4-1.1-0.4c-0.9,0-1.5,0.6-1.5,1.5
c0,0.9,0.6,1.5,1.5,1.5c0.5,0,0.9-0.2,1.2-0.5l0.3,0.4c-0.4,0.4-1,0.6-1.5,0.6C141.3,45,140.4,44.3,140.4,43z"/>
<path d="M146.5,43.7v-3.8h-1.4v-0.5h2v4.4c0,0.6,0.3,0.8,0.8,0.8c0.2,0,0.5-0.1,0.7-0.2l0.2,0.5c-0.4,0.2-0.6,0.2-1,0.2
C146.9,45,146.5,44.6,146.5,43.7z"/>
<path d="M149.9,44c0-0.9,0.8-1.3,2.8-1.4c0-0.5-0.3-1-1-1c-0.5,0-1,0.2-1.3,0.5l-0.3-0.4c0.4-0.3,1-0.6,1.7-0.6
c1.1,0,1.6,0.6,1.6,1.6v2.4h-0.5l-0.1-0.5h0c-0.4,0.3-1,0.6-1.5,0.6C150.5,45,149.9,44.6,149.9,44z M152.7,43.9v-1
c-1.6,0.1-2.1,0.5-2.1,1c0,0.4,0.4,0.6,0.8,0.6C151.8,44.5,152.3,44.3,152.7,43.9z"/>
<path d="M154.6,44.4l0.3-0.4c0.4,0.3,1,0.5,1.7,0.5c0.6,0,1-0.3,1-0.6c0-0.3-0.2-0.5-1.2-0.7c-1-0.2-1.5-0.5-1.5-1.1
c0-0.6,0.5-1.1,1.6-1.1c0.6,0,1.2,0.2,1.6,0.5l-0.3,0.4c-0.4-0.2-0.8-0.4-1.3-0.4c-0.6,0-0.9,0.3-0.9,0.6c0,0.3,0.3,0.5,1.1,0.6
c1.3,0.3,1.6,0.6,1.6,1.2c0,0.6-0.6,1.1-1.7,1.1C155.7,45,155.1,44.8,154.6,44.4z"/>
<path d="M159.3,44.4l0.3-0.4c0.4,0.3,1,0.5,1.7,0.5c0.6,0,1-0.3,1-0.6c0-0.3-0.2-0.5-1.2-0.7c-1-0.2-1.5-0.5-1.5-1.1
c0-0.6,0.5-1.1,1.6-1.1c0.6,0,1.2,0.2,1.6,0.5l-0.3,0.4c-0.4-0.2-0.8-0.4-1.3-0.4c-0.6,0-0.9,0.3-0.9,0.6c0,0.3,0.3,0.5,1.1,0.6
c1.3,0.3,1.6,0.6,1.6,1.2c0,0.6-0.6,1.1-1.7,1.1C160.5,45,159.8,44.8,159.3,44.4z"/>
<path d="M164.2,41.2h3.4v0.5h-3.4V41.2z M164.2,42.9h3.4v0.5h-3.4V42.9z"/>
<path d="M169.3,40.4l0-0.9h0.9l0,0.9l-0.2,1.8h-0.4L169.3,40.4z M171.2,40.4l0-0.9h0.9l0,0.9l-0.2,1.8h-0.4L171.2,40.4z"/>
<path d="M174.2,41.1h0.5l0.1,0.9h0c0.4-0.6,1-1,1.7-1c0.3,0,0.5,0,0.8,0.2l-0.2,0.6c-0.3-0.1-0.4-0.1-0.7-0.1
c-0.6,0-1.1,0.3-1.6,1.1v2.2h-0.7V41.1z"/>
<path d="M180.3,41.6h-1.8v-0.5h2.4v3.8h-0.7V41.6z M180,39.8c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5c0,0.3-0.2,0.5-0.5,0.5
S180,40.1,180,39.8z"/>
<path d="M183.1,45.7c0-0.3,0.2-0.6,0.6-0.9v0c-0.2-0.1-0.4-0.3-0.4-0.6c0-0.2,0.2-0.5,0.5-0.7v0c-0.3-0.2-0.5-0.5-0.5-1
c0-0.8,0.7-1.4,1.5-1.4c0.2,0,0.4,0,0.6,0.1h1.6v0.5h-1c0.2,0.2,0.3,0.5,0.3,0.8c0,0.8-0.7,1.3-1.5,1.3c-0.2,0-0.4,0-0.6-0.1
c-0.2,0.1-0.3,0.3-0.3,0.4c0,0.3,0.3,0.4,0.8,0.4h0.9c1,0,1.5,0.3,1.5,0.9c0,0.7-0.8,1.3-2.1,1.3
C183.8,46.7,183.1,46.3,183.1,45.7z M186.4,45.5c0-0.4-0.3-0.5-0.9-0.5h-0.8c-0.2,0-0.4,0-0.6-0.1c-0.4,0.2-0.5,0.4-0.5,0.6
c0,0.4,0.4,0.7,1.3,0.7C185.9,46.2,186.4,45.9,186.4,45.5z M185.8,42.4c0-0.5-0.4-0.9-0.9-0.9c-0.5,0-0.9,0.4-0.9,0.9
c0,0.6,0.4,0.9,0.9,0.9C185.4,43.3,185.8,42.9,185.8,42.4z"/>
<path d="M188.1,39.3h0.7v1.5l0,0.9h0c0.4-0.4,0.8-0.8,1.4-0.8c0.9,0,1.3,0.5,1.3,1.6v2.4h-0.7v-2.3c0-0.7-0.3-1.1-0.9-1.1
c-0.5,0-0.8,0.2-1.2,0.7v2.7h-0.7V39.3z"/>
<path d="M193.7,43.5v-1.8h-1.1v-0.5l1.1,0l0.1-1.2h0.5v1.2h1.9v0.5h-1.9v1.8c0,0.7,0.2,1,1,1c0.4,0,0.6-0.1,0.9-0.2l0.1,0.5
c-0.3,0.1-0.7,0.2-1.2,0.2C194.1,45,193.7,44.4,193.7,43.5z"/>
<path d="M197.5,42.1h3.4v0.5h-3.4V42.1z"/>
<path d="M202.1,43c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4h-3.3v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C203,45,202.1,44.3,202.1,43z"/>
<path d="M208.3,43.7v-3.8h-1.4v-0.5h2v4.4c0,0.6,0.3,0.8,0.8,0.8c0.2,0,0.5-0.1,0.7-0.2l0.2,0.5c-0.4,0.2-0.6,0.2-1,0.2
C208.7,45,208.3,44.6,208.3,43.7z"/>
<path d="M211.6,43c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4h-3.3v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C212.6,45,211.6,44.3,211.6,43z"/>
<path d="M216.3,41.1h0.5l0.1,0.5h0c0.2-0.4,0.4-0.6,0.9-0.6c0.4,0,0.6,0.2,0.7,0.7c0.2-0.4,0.5-0.7,0.9-0.7
c0.5,0,0.9,0.4,0.9,1.2v2.8h-0.6v-2.7c0-0.4-0.1-0.7-0.4-0.7c-0.3,0-0.4,0.2-0.6,0.6v2.8H218v-2.7c0-0.4-0.1-0.7-0.4-0.7
c-0.3,0-0.4,0.2-0.6,0.6v2.8h-0.6V41.1z"/>
<path d="M221.2,43c0-1.3,0.9-2,2-2c1.1,0,1.8,0.7,1.8,1.8c0,0.2,0,0.3,0,0.4h-3.3v-0.5h2.9l-0.2,0.2c0-0.9-0.5-1.4-1.2-1.4
c-0.7,0-1.3,0.5-1.3,1.5c0,1,0.6,1.5,1.5,1.5c0.5,0,0.8-0.1,1.2-0.4l0.2,0.4c-0.4,0.3-0.9,0.5-1.5,0.5
C222.1,45,221.2,44.3,221.2,43z"/>
<path d="M226.1,41.1h0.5l0.1,0.6h0c0.4-0.4,0.8-0.7,1.4-0.7c0.9,0,1.3,0.5,1.3,1.6v2.4h-0.7v-2.3c0-0.7-0.3-1.1-0.9-1.1
c-0.5,0-0.8,0.2-1.2,0.7v2.7h-0.7V41.1z"/>
<path d="M231.8,43.5v-1.8h-1.1v-0.5l1.1,0l0.1-1.2h0.5v1.2h1.9v0.5h-1.9v1.8c0,0.7,0.2,1,1,1c0.4,0,0.6-0.1,0.9-0.2l0.1,0.5
c-0.3,0.1-0.7,0.2-1.2,0.2C232.1,45,231.8,44.4,231.8,43.5z"/>
<path d="M235.9,40.4l0-0.9h0.9l0,0.9l-0.2,1.8h-0.4L235.9,40.4z M237.7,40.4l0-0.9h0.9l0,0.9l-0.2,1.8h-0.4L237.7,40.4z"/>
</g>
</g>
</g>
</g>
</svg>
import imageSrc, { prefix as imagePrefix } from "@/assets/targeting-demo.svg";
export function main() {
document.getElementById("app")!.innerHTML += `
<p class="demo-section-caption">Click on the rectangles to change their colors:</p>
<div class="images">
<div id="image" class="standalone-image">
${imageSrc}
</div>
</div>
`;
const createColorGetter = (colors: string[]) => {
let index = 0;
return () => {
index++;
if (index === colors.length) {
index = 0;
}
return colors[index];
};
};
const leftElementClass = imagePrefix + "left-element";
const rightElementClass = imagePrefix + "right-element";
const getLeftElementColor = createColorGetter(["#ffd6d6", "#e8ffd6", "#d6efff"]);
const getRightElementColor = createColorGetter(["#f3d6ff", "#ffffd6", "#dad6ff"]);
document.getElementById("image")!.addEventListener("click", (e: MouseEvent) => {
if (!(e.target instanceof SVGElement)) {
return;
}
if (e.target.classList.contains(leftElementClass)) {
e.target.style.fill = getLeftElementColor();
} else if (e.target.classList.contains(rightElementClass)) {
e.target.style.fill = getRightElementColor();
}
});
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1"
/>
</head>
<body>
<div id="app"></div>
<script type="module">
import { main } from "./src/main.ts";
main();
</script>
</body>
</html>
{
"name": "vanilla-svg-nodes-targeting",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "npm run build -- --watch",
"build": "npm run type-check && npm run build-only",
"build-only": "vite build --config vite.config.lib.ts",
"type-check": "tsc --noEmit",
"lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"vite-awesome-svg-loader": "*",
"vite-file-tree-builder": "*",
"vite-astro-entry-generator": "*"
}
}
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"types": [
// Add types for query imports (for example, "@/some/file.svg?src").
// Unfortunately, it's impossible to fully type it. Use plugin configuration instead.
"vite-awesome-svg-loader",
"vite/client", // Vite types
"vite-file-tree-builder" // Internal types
]
},
"include": ["src"]
}
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
// Import vite-awesome-svg-loader
import { viteAwesomeSvgLoader } from "vite-awesome-svg-loader";
export default defineConfig({
plugins: [viteAwesomeSvgLoader({ urlImportsInLibraryMode: "emit-files" })],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
Please open file to view its content