Multicolored icons
The recommended solution is to use CSS variables in SVG images. This way, we won’t need to replace whole images set when only one color in the palette changes.
This method allows designers and developers to work seamlessly and share same icon sets without any additional manual modifications.
vite-awesome-svg-loader
allows you to map a set of predefined colors (or any values for that matter) to a set of CSS
variables (or any other values) via
replaceColorsList option:
export default defineConfig({ plugins: [ viteAwesomeSvgLoader({ replaceColorsList: // Global map of color replacements. Key is an original color, value is its replacement. Both can be any values: // HEX, name, rgb() or arbitrary custom values. Applied to all files. { "#003147": "red", "rgb(0, 49, 71)": "#003147", "myCustomColor": "var(--some-color-var)", },
// Map of color replacements per files { files: ["vars.svg"], // File names or regexes
// Replacements, same format as above replacements: { red: "var(--primary-color)", green: "var(--secondary-color)", blue: "var(--tertiary-color)", },
// Default value for colors that are not in replacements map. Set an empty string to preserve original colors. // Default value is "currentColor", default: "currentColor" }, }), ],});
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 24 24" xml:space="preserve"> <circle fill="red" cx="8.0524569" cy="8.1588478" r="7.8950858" />
<circle fill="blue" cx="15.9475431" cy="8.1588478" r="7.8950858" />
<circle fill="green" cx="12" cy="15.8411522" r="7.8950858" />
<style type="text/css"> circle { opacity: 0.5; } </style></svg>
import imageSrc from "@/assets/image.svg";import { CSSProperties } from "react";import { SvgImage } from "vite-awesome-svg-loader/react-integration";
export default function App() { return ( <div className="images"> <SvgImage src={imageSrc} className="image" style={ { "--primary-color": "red", "--secondary-color": "green", "--tertiary-color": "blue", } as CSSProperties } /> <SvgImage src={imageSrc} className="image" style={ { "--primary-color": "magenta", "--secondary-color": "cyan", "--tertiary-color": "yellow", } as CSSProperties } /> </div> );}
import React from "react";import ReactDOM from "react-dom/client";import App from "./App.tsx";
ReactDOM.createRoot(document.getElementById("app")!).render( <React.StrictMode> <App /> </React.StrictMode>,);
/// <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.tsx" ></script> </body></html>
{ "name": "react-multicolored-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,tsx --report-unused-disable-directives --max-warnings 0" }, "dependencies": { "vite-awesome-svg-loader": "*", "vite-file-tree-builder": "*" }}
{ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true,
/* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx",
/* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true,
"baseUrl": ".", "paths": { "@/*": ["./src/*"] } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }],}
{ "compilerOptions": { "composite": true, "skipLibCheck": true, "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"]}
import { fileURLToPath, URL } from "node:url";import { defineConfig } from "vite";import react from "@vitejs/plugin-react";
// Import vite-awesome-svg-loaderimport { viteAwesomeSvgLoader } from "vite-awesome-svg-loader";
export default defineConfig({ plugins: [ react(), viteAwesomeSvgLoader({ replaceColorsList: [ { files: ["image.svg"], // File names or regexes
// Replacements, same format as above replacements: { red: "var(--primary-color)", green: "var(--secondary-color)", blue: "var(--tertiary-color)", },
// Default value for colors that are not in replacements map. Set an empty string to preserve original colors. // Default value is "currentColor", default: "currentColor", }, ],
urlImportsInLibraryMode: "emit-files", }), ], resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)), }, },});
Please open file to view its content