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>
<template> <p class="demo-section-caption">Click on the rectangles to change their colors:</p>
<div class="images"> <div v-html="imageSrc" class="standalone-image" @click="onClick" /> </div></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");
/// <reference types="vite/client" />
// Link some of the import configs. Unfortunately, it's impossible to fully type it. Use plugin configuration instead.// Use import config when you really need it to avoid @ts-ignore before every import./// <reference types="vite-awesome-svg-loader" />
// Internal types/// <reference types="vite-file-tree-builder" />
<!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", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" }, "dependencies": { "vite-awesome-svg-loader": "*", "vite-file-tree-builder": "*" }}
{ "extends": "@vue/tsconfig/tsconfig.dom.json", "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], "exclude": ["src/**/__tests__/*"], "compilerOptions": { "composite": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"] } }}
{ "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-loaderimport { 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