vitejs-svg-plugin
v1.1.0
Published
[](https://www.npmjs.com/package/vitejs-svg-plugin) [](https://opensource.org/licenses/MIT)
Maintainers
Readme
vitejs-svg-plugin
A Vite plugin that automatically loads, optimizes, and registers SVG files as inline symbols for efficient usage in your projects.
Features
- ✅ Recursively scans SVG files from the configured directory, subdirectories included
- ✅ Derives stable, normalized icon IDs from the file path (
menu/add.svg→#icon_menu-add) - ✅ Warns about duplicate or case-conflicting icon names without breaking the build
- ✅ Optimizes SVGs using SVGO for smaller file sizes
- ✅ Supports configurable ID prefix for SVG symbols
- ✅ Sets
fill="currentColor"and removes hardcoded colors so icons follow the parentcolor - ✅ Removes width/height attributes for flexible sizing
- ✅ Registers SVGs as inline symbols in the DOM for efficient rendering
- ✅ Emits the icon payload as a dedicated
svg-iconschunk - ✅ Generates TypeScript type definitions for SVG icon names
- ✅ Supports CSS mode for using SVGs as URL-encoded CSS data URIs
- ✅ Watches the icon directory during dev and reloads automatically — no restart needed
- ✅ Works with Vite 3, 4, 5, 6, and 7
Installation
npm install vitejs-svg-plugin --save-devOr using pnpm:
pnpm add -D vitejs-svg-pluginUsage
Basic Configuration
Add the plugin to your vite.config.ts:
import { defineConfig } from 'vite'
import { createSvgLoader } from 'vitejs-svg-plugin'
export default defineConfig({
plugins: [
createSvgLoader({
path: 'src/assets/svg'
})
]
})Advanced Configuration
import { defineConfig } from 'vite'
import { createSvgLoader } from 'vitejs-svg-plugin'
export default defineConfig({
plugins: [
createSvgLoader({
path: 'src/assets/svg',
prefix: 'icon', // Default: 'icon'
css: false, // Default: false
output: 'src/types/svg-icons.d.ts',
entry: 'src/main.ts', // Default: auto-detected
recursive: true, // Default: true
keepOriginalColor: false // Default: false
})
]
})Entry Injection
The plugin injects import 'virtual:svg-loader' into your entry file, which registers the icons. By default the entry is auto-detected (see the entry option). If auto-detection cannot find an entry, or if you set entry: false, add the import manually:
// src/main.ts
import 'virtual:svg-loader'Usage in Components
Once the loader is imported, you can use SVG icons in your components:
Vue:
<template>
<svg class="icon">
<use :xlink:href="'#icon_home'" />
</svg>
</template>React:
const Icon = ({ name }: { name: string }) => (
<svg className="icon">
<use xlinkHref={`#icon_${name}`} />
</svg>
)Configuration Options
path (required)
Type: string
The directory path where your SVG files are located, resolved relative to Vite's config.root. The plugin scans this directory for .svg files, and by default it also scans every subdirectory.
path: 'src/assets/icons'prefix (optional)
Type: string
Default: 'icon'
The prefix to use for SVG symbol IDs, joined with _. This helps avoid ID conflicts when multiple SVG plugins are used.
prefix: 'my-icon' // Results in IDs like: my-icon_home, my-icon_menu-addcss (optional)
Type: boolean
Default: false
Enable CSS mode to use SVGs as CSS masks. When enabled, the plugin generates CSS classes with URL-encoded data URIs instead of SVG symbols.
css: trueCSS Mode Usage:
.icon-home {
...
}
.icon-user {
...
}<template>
<div class="icon-home"></div>
<div class="icon-user"></div>
</template>output (optional)
Type: string
Path to generate a TypeScript file containing icon names. This enables type-safe icon usage. Missing parent directories are created automatically, and the file is rewritten whenever the icon set changes (including while the dev server is running).
output: 'src/types/svg-icons.d.ts'Generated file example:
/**
* Svg Icon names (vitejs-svg-plugin)
* @author SinJay Xie
* @date 6/23/2026, 11:25:22 AM
* @description Load SVG amount: 2
*/
export type SvgIconNames = 'add' | 'add2' | (string & {});entry (optional)
Type: string | RegExp | string[] | false
The entry file(s) that should receive import 'virtual:svg-loader':
string: a path relative to the project root (config.root)RegExp: matched against module IDsstring[]: any of the listed pathsfalse: disables automatic injection — addimport 'virtual:svg-loader'manually
When entry is not configured, the plugin probes for an entry in this order: build.rollupOptions.input (JS/TS entries) → the <script src> in the root index.html. Injection is skipped automatically for library builds (build.lib) and SSR builds. If nothing is detected, the plugin logs a warning suggesting entry or a manual import 'virtual:svg-loader'.
entry: 'src/app.ts'recursive (optional)
Type: boolean
Default: true
Recursively scan all subdirectories of path. Set to false to scan only the top level, which matches the legacy behavior.
recursive: falsekeepOriginalColor (optional)
Type: boolean
Default: false
By default the plugin removes hardcoded fill/stroke from icon child elements (both attributes and inline style) so the icon color is fully controlled by currentColor — set color on any ancestor to recolor the icon. fill="none" and fill="currentColor" are always preserved. Set this option to true to keep the original colors.
keepOriginalColor: truesvgoOptions (optional)
Type: svgo Config
Overrides for the SVGO pipeline. By default the plugin runs preset-default plus its own plugins (remove width/height, inject fill="currentColor" and the symbol id) and always keeps viewBox. When you provide plugins, your list is used as-is instead of the default plugins.
createSvgLoader({
path: 'src/assets/svg',
svgoOptions: {
// This list replaces the default plugin list
plugins: [
'preset-default',
{ name: 'removeAttrs', params: { attrs: ['width', 'height'] } },
{ name: 'addAttributesToSVGElement', params: { attribute: { fill: 'currentColor' } } }
]
}
})How It Works
Icon IDs
An icon ID is the file path relative to path, without the extension, joined with -, and prefixed with ${prefix}_:
add.svg→#icon_addmenu/add.svg→#icon_menu-add
Whitespace and the characters # % & " ' < > = / \ ( ) are replaced with -, and consecutive - are collapsed, so my icon (1).svg becomes #icon_my-icon-1. Files that resolve to the same ID (including names that differ only by case) trigger a warning, and the first icon in the sorted order is kept.
Default Mode (SVG Symbols)
- Scan: The plugin recursively scans the specified directory for all
.svgfiles and derives normalized IDs - Optimize: Each SVG is optimized using SVGO with
preset-defaultplus plugins that:- remove
width/heightattributes for flexible sizing - inject
fill="currentColor"and the symbolid - remove hardcoded child
fill/strokecolors (unlesskeepOriginalColor: true) - keep
viewBoxso icons stay scalable
- remove
- Convert: SVG elements are converted to
<symbol>elements - Register: Symbols are injected into the DOM as a hidden SVG container (skipped when
documentis unavailable) - Use: You can reference any SVG using
<use xlink:href="#prefix_name" />
CSS Mode
When css: true is enabled:
- Scan: The plugin recursively scans the specified directory for all
.svgfiles - Optimize: Each SVG is optimized using SVGO with
datauri: 'enc', producing a URL-encodeddata:image/svg+xml,...payload - Generate CSS: Creates CSS classes (e.g.
.icon-home) that apply the SVG through CSS variables and masks, colored bycurrentColor - Use: Apply CSS classes to elements to display SVG icons
Development
While the dev server is running, the plugin watches the icon directory. Adding, deleting, or modifying an SVG file triggers a re-scan and a page reload, and the file specified by output is updated at the same time — no restart required. The same re-scan happens in vite build --watch mode.
Example Project Structure
src/
├── assets/
│ └── svg/
│ ├── home.svg
│ ├── user.svg
│ └── menu/
│ └── add.svg
├── components/
│ └── Icon.vue
└── main.tsThis produces the IDs #icon_home, #icon_user, and #icon_menu-add.
TypeScript Support
When using the output option, the plugin generates type definitions that allow you to:
- Get autocomplete for icon names
- Use the generated
SvgIconNamestype for type-safe icon usage - Still pass any string (the type ends with
(string & {}), sostringdoes not collapse the union)
Example with TypeScript:
import type { SvgIconNames } from '@/types/svg-icons'
// Type-safe icon usage with autocomplete
const icon: SvgIconNames = 'home'
// Arbitrary strings are still allowed
const custom: SvgIconNames = 'home-custom'When no icons are found, the generated type is string & {}.
License
MIT © sinjayxie
