Usage
Standard setup
The typical integration has three parts:
Add the plugin to
vite.config.tstsimport { resolve } from 'node:path'; import { defineConfig } from 'vite'; import viteSvgToWebfont from 'vite-svg-2-webfont'; export default defineConfig({ plugins: [ viteSvgToWebfont({ context: resolve(import.meta.dirname, 'icons'), }), ], });Import
virtual:vite-svg-2-webfont.csstsimport 'virtual:vite-svg-2-webfont.css';Use generated class names in markup, for example:
html<i class="icon icon-add"></i>
How class names are generated
- The default base selector is
.icon, seebaseSelector - The default class prefix is
icon-, seeclassPrefix - SVG file names become icon names (e.g.
add.svgbecomes{classPrefix}add)
For example, if context contains add.svg, the generated CSS class is icon-add, and you would use it like this:
<i class="icon icon-add"></i>If you want different class names, change classPrefix and baseSelector.
Development file output
By default, the plugin does not write generated assets to disk during development. If you want preview artifacts while iterating, use generateFiles to enable file output and specify which files to generate:
viteSvgToWebfont({
context: './src/icons',
generateFiles: ['css', 'fonts', 'html'],
});Build-time behavior
- Preload tags can be injected into built HTML with
preloadFormats - Preload injection can be limited to selected HTML entrypoints with
shouldProcessHtml - When
inlineistrue, no preload tags are injected because assets are embedded in the CSS - Direct generator file output during build is disabled unless
allowWriteFilesInBuildis enabled; Vite still bundles fonts referenced by the virtual CSS import
Configure production font output
With the standard setup, Vite processes the virtual CSS and bundles its referenced fonts. Vite's build settings control their output paths; the plugin's dest option controls additional generator files.
To change the directory for all bundled assets, set build.assetsDir:
export default defineConfig({
plugins: [viteSvgToWebfont({ context: './src/icons' })],
build: {
assetsDir: 'static',
assetsInlineLimit: 0,
},
});With the default build.outDir, emitted assets go into dist/static/. Setting assetsInlineLimit: 0 prevents Vite from embedding small fonts as data URLs. Keep the plugin's inline option disabled when you want separate font files.
To place fonts in their own directory while keeping other assets under assets/, configure build.rolldownOptions.output.assetFileNames instead. The example below uses Vite 8 or newer, where Rolldown is the default bundler. On Rollup-based Vite 6 or 7, use build.rollupOptions.output.assetFileNames instead (replace rolldownOptions with rollupOptions):
export default defineConfig({
plugins: [viteSvgToWebfont({ context: './src/icons' })],
build: {
assetsInlineLimit: 0,
rolldownOptions: {
output: {
assetFileNames: asset => (asset.names.some(name => /\.(woff2?|ttf|eot)$/i.test(name)) ? 'fonts/[name]-[hash][extname]' : 'assets/[name]-[hash][extname]'),
},
},
},
});This emits matching fonts under dist/fonts/. The rule applies to all matching font assets in the application. SVG fonts use .svg, so this example leaves them under assets/ alongside other SVG assets.
Vite updates the bundled CSS URLs to match the emitted paths. Use Vite's base for the public base path; the plugin's cssFontsUrl does not override URLs in the bundled virtual CSS.
Write additional generator files during builds
To write fonts directly to dest during a production build, enable both generateFiles and allowWriteFilesInBuild:
viteSvgToWebfont({
context: './src/icons',
dest: './generated-fonts',
generateFiles: true,
allowWriteFilesInBuild: true,
});The generator writes font files such as generated-fonts/iconfont.woff2, plus CSS and HTML at their configured destinations (also under dest by default). Use generateFiles: 'fonts' to write only the fonts.
When the application also imports the virtual CSS, Vite bundles its own copies of the referenced fonts. These directly generated files are additional output; they do not move or replace Vite's bundled assets.
Multi-weight icon families
To use light and bold versions of the same icons, put matching filenames in each design directory, for example src/icons/light/add.svg and src/icons/bold/add.svg.
Configure the designs instead of top-level
files:tsviteSvgToWebfont({ context: './src/icons', fontName: 'icons', variants: [ { name: 'light', context: 'light', weight: 300, default: true }, { name: 'bold', context: 'bold', weight: 700 }, ], });Keep the existing virtual CSS import:
tsimport 'virtual:vite-svg-2-webfont.css';Add the modifier for a non-default design:
html<span class="icon icon-add" aria-hidden="true"></span> <span class="icon icon-add icon--bold" aria-hidden="true"></span>
The first icon uses light artwork; the second uses bold artwork. The family produces one shared WOFF and one shared WOFF2 by default. Select types: ['ttf', 'woff', 'woff2'] (any one of these 3 valid formats) to change the formats. SVG/EOT output is available only in ordinary mode.
For nested input folders, set a design's files to ['**/*.svg']. To use sparse designs (ie. some variants have glyphs which other variants do not), configure missingGlyphs; each design must still contain at least one SVG.
Edits across the design roots are batched and regenerated through one serialized queue. The plugin refreshes every design's membership, updates shared font bytes, and reloads virtual CSS, including in inline mode. Invalid edits leave the last successful in-memory output available; the plugin reports the error and retries on subsequent changes. Optional filesystem output remains non-transactional.
Custom CSS callbacks are invoked again through full generation. Existing CSS/SCSS/HTML templates, selectors, optional disk output, and preload controls also apply to families. Shared assets are emitted and preloaded once per selected format, not once per design.
See multi-weight icon families to configure multiple designs; they use the same output controls.
Related options
Common options you may want to adjust early:
See the full Configuration reference for details.