Named icons
Named icons must be implemented on your side using import.meta.glob()
or, given your circumstances, another method.
Named icons are not present in the integrations because glob imports don’t support variable interpolation. See: https://vitejs.dev/guide/features#glob-import.
The demo below presents an example implementation of named icons.
Rendered demo
Demo's source code
src
assets
icons
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M21 5v6.59l-3-3.01l-4 4.01l-4-4l-4 4l-3-3.01V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2m-3 6.42l3 3.01V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-6.58l3 2.99l4-4l4 4"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M6 2v6l4 4l-4 4v6h12v-6l-4-4l4-4V2z"/></svg>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.28003 22C8.00316 22 9.40003 20.6031 9.40003 18.88C9.40003 17.1569 8.00316 15.76 6.28003 15.76C4.55691 15.76 3.16003 17.1569 3.16003 18.88C3.16003 20.6031 4.55691 22 6.28003 22Z" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M20.84 16.8001V4.60009C20.84 2.00009 19.21 1.64009 17.56 2.09009L11.32 3.79009C10.18 4.10009 9.40002 5.00009 9.40002 6.30009V8.47009V9.93009V18.8701" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M17.72 19.9199C19.4431 19.9199 20.84 18.5231 20.84 16.7999C20.84 15.0768 19.4431 13.6799 17.72 13.6799C15.9968 13.6799 14.6 15.0768 14.6 16.7999C14.6 18.5231 15.9968 19.9199 17.72 19.9199Z" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.40002 9.5199L20.84 6.3999" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.73 3.51001L15.49 7.03001C15.73 7.52002 16.37 7.99001 16.91 8.08001L20.1 8.61001C22.14 8.95001 22.62 10.43 21.15 11.89L18.67 14.37C18.25 14.79 18.02 15.6 18.15 16.18L18.86 19.25C19.42 21.68 18.13 22.62 15.98 21.35L12.99 19.58C12.45 19.26 11.56 19.26 11.01 19.58L8.01997 21.35C5.87997 22.62 4.57997 21.67 5.13997 19.25L5.84997 16.18C5.97997 15.6 5.74997 14.79 5.32997 14.37L2.84997 11.89C1.38997 10.43 1.85997 8.95001 3.89997 8.61001L7.08997 8.08001C7.61997 7.99001 8.25997 7.52002 8.49997 7.03001L10.26 3.51001C11.22 1.60001 12.78 1.60001 13.73 3.51001Z" stroke="green" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.53 20.4201H6.21C3.05 20.4201 2 18.3201 2 16.2101V7.79008C2 4.63008 3.05 3.58008 6.21 3.58008H12.53C15.69 3.58008 16.74 4.63008 16.74 7.79008V16.2101C16.74 19.3701 15.68 20.4201 12.53 20.4201Z" stroke="#7272ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M19.52 17.0999L16.74 15.1499V8.83989L19.52 6.88989C20.88 5.93989 22 6.51989 22 8.18989V15.8099C22 17.4799 20.88 18.0599 19.52 17.0999Z" stroke="#7272ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M11.5 11C12.3284 11 13 10.3284 13 9.5C13 8.67157 12.3284 8 11.5 8C10.6716 8 10 8.67157 10 9.5C10 10.3284 10.6716 11 11.5 11Z" stroke="#7272ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
import loadingIcon from "@/assets/icons/hourglass.svg";import errorIcon from "@/assets/icons/broken-image.svg";import { ElementOrSelector, SvgIcon } from "vite-awesome-svg-loader/vanilla-integration";
// See: https://vitejs.dev/guide/features#glob-importconst rawIcons: any = import.meta.glob("/src/assets/icons/*.svg", { // Put URL here or setup your imports via vite-awesome-svg-loader configuration query: "?preserve-line-width&set-current-color",});
// Transform keys from paths to file-based icon names
const icons: any = {};
for (const path in rawIcons) { let name = path.split("/").pop() || ""; name = name.substring(0, name.lastIndexOf(".")); icons[name] = rawIcons[path];}
export class NamedIcon extends SvgIcon { protected name = "";
constructor(name: string, mountTo?: ElementOrSelector) { super(loadingIcon, mountTo); this.setName(name); }
async setName(name: string) { this.name = name; let code = errorIcon;
try { code = (await icons[name]()).default; // Fetch SVG source code } catch (e) { console.error(e); code = errorIcon; // Provide a fallback for when icon could not be loaded }
// Verify that name hasn't changed. If it didn't, set its source code. Otherwise other setName() // call will handle the changes. if (name === this.name) { this.setSrc(code); } }
getName() { return this.name; }}
import { NamedIcon } from "@/NamedIcon";
export function main() { // Initial markup
document.getElementById("app")!.innerHTML += ` <div id="icons" class="images" > </div> `;
// Create icons
const icons = ["music", "star", "video"]; const container = document.getElementById("icons")!;
for (const name of icons) { new NamedIcon(name, container).setColor("orange").getSvgEl().classList.add("image"); }}
/// <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"> import { main } from "./src/main.ts"; main(); </script> </body></html>
{ "name": "vanilla-named-icons", "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/*"] } }, "include": ["src"]}
import { fileURLToPath, URL } from "node:url";import { defineConfig } from "vite";
// Import vite-awesome-svg-loaderimport { 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