Skip to content

SVG nodes targeting

Sometimes, it is required to change a specific SVG node’s style, or make it interactive. In other words, nodes targeting is required.

This is possible with vite-awesome-svg-loader with one condition: all IDs and classes of every SVG elements are prefixed with a unique string to avoid collisions.

This prefix can be extracted like so:

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

Then a node can be selected like so:

document.getElementById(imagePrefix + "some-svg-node");

The demo below changes element’s colors when user clicks on it. Each element has its own color map. The targeting is implemented by accessing nodes with their class names.

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>
<template>
<p class="demo-section-caption">Click on the rectangles to change their colors:</p>
<div
v-html="imageSrc"
class="standalone-image"
@click="onClick"
/>
</template>
<script setup lang="ts">
import imageSrc, { prefix as imagePrefix } from "@/assets/targeting-demo.svg";
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"]);
const onClick = (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();
}
};
</script>
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
<!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"
src="/src/main.ts"
></script>
</body>
</html>
{
"name": "vue-svg-nodes-targeting",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "npm run build-only -- --watch",
"build": "run-p type-check \"build-only {@}\" --",
"build-only": "vite build --config vite.config.lib.ts",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false"
},
"dependencies": {
"vite-awesome-svg-loader": "*",
"vite-file-tree-builder": "*"
}
}
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["src/**/*", "src/**/*.vue"],
"compilerOptions": {
"composite": 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
]
}
}
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}
{
"extends": "@tsconfig/node18/tsconfig.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "nightwatch.conf.*", "playwright.config.*"],
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// Import vite-awesome-svg-loader
import { viteAwesomeSvgLoader } from "vite-awesome-svg-loader";
export default defineConfig({
plugins: [vue(), viteAwesomeSvgLoader({ urlImportsInLibraryMode: "emit-files" })],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
Please open file to view its content