This library generates icon components on demand. It works with multiple frameworks and bundlers.
It uses Iconify as source for icons, which offers over 200 open source icon sets with almost 300k icons.
<script setup>
import BellIcon from '/~iconify/mdi-light/bell';
</script>
<template>
<BellIcon height="1em" />
</template>The big difference from other solutions is, icons are split into SVG and CSS parts.
Instead of rendering full SVG like this:
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M6 17c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6m9-9a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3a3 3 0 0 1 3 3M3 5v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2" />
</svg>Iconify Unplugin renders smaller SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path class="mdi-account-box" />
</svg>and moves all shapes to CSS:
.mdi-account-box {
fill: currentColor;
d: path(
'M6 17c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6m9-9a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3a3 3 0 0 1 3 3M3 5v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2'
);
}See SVG + CSS for details.
Why is this better?
- Reduces HTML size, especially noticesable when the same icon is used multiple times.
- CSS is cached, so icon content is cached by browser instead of being included in HTML.
Plugin uses hashing to generate unique class names. This prevents duplication and avoids collissions.
There is one issue with rendering SVG+CSS: currently Safari browser does not support d attribute for <path /> in CSS.
To work around this issue, components include dynamic fallback, which is loaded and rendered only for outdated browsers.
See solving Safari fallback for SVG+CSS.
In future, when Safari will finally join the modern browsers (hopefully soon because Safari Technology Preview supported this since 2024), fallback can be removed. This will make it possible to add support for more frameworks and render icons as raw HTML strings, not components.
To support Safari browser, you need to install the following dev dependencies:
- For Vue:
@iconify/css-vue - For Svelte:
@iconify/css-svelte - For React and Preact:
@iconify/css-react
There are no fallback components for other frameworks. If you are not using frameworks listed above, your options are:
- Ignore Safari users (bad option).
- Render full SVG instead of SVG+CSS (see plugin options below).
Iconify Unplugin supports several compilers.
Compilers with a fallback for Safari browser:
vue- generates Vue 3 components.svelte- generates Svelte 5 components (uses runes).react- generates React components.preact- generates Preact components.
Compilers without a fallback, so icons will work only in modern browsers:
raw- generates icon as string, can be used in with framework (seevite-vueandvite-svelteexamples for usage).
Installation depends on bundler and framework you are using.
See examples in examples directory for... examples.
First step is to install @iconify/unplugin as a dependency.
For Vite, open vite.config.js, add import statement for plugin and plugin entry in plugins property.
Example configuration:
import { defineConfig } from 'vite';
import Icons from '@iconify/unplugin/vite';
export default defineConfig({
plugins: [
Icons({
// Change to 'vue' for Vue, 'react' for React, etc...
compiler: 'svelte',
}),
],
});Syntax for other bundlers is similar to example above:
- Replace "vite" with bundler name. Supported bundlers: "esbuild", "farm", "rollup", "rspack", "webpack".
- Add plugin to plugins list. Plugin options are the same for all bundlers.
Plugin accepts the following options:
- compiler: default "compiler" value for icons.
- namespace: change URL from "iconify" to something else, allowing you to use multiple instances of plugin with different options.
- mode: rendering mode, default is "svg+css". Supported values are "svg+css" and "svg" to render full SVG.
- css: rendering mode for stylesheet, default is "import".
See src/plugin/types/options.ts for full list of options.
Most of these options are used in examples. See "examples" directory.
Some of these options can be overwritten for each icon by adding URL parameters. If both URL parameter and config value are set, URL parameter is used.
Plugin supports several modes for rendering SVG+CSS icons, which can be set in "css" option or URL parameter:
- "import": styles are split in separate files, imported from package. This reduces duplication.
- "module": uses CSS modules. This is not advised because it generates much longer class names without providing any benefit. However, some frameworks, such as Next.js and Qwik, intentionally do not support importing css files, so this is an option if you are using one of those frameworks.
- "embed": embeds CSS in SVG using
<style>tag.
Default value is "import".
Plugin does not include icons.
If you want access to all icons, add @iconify/json as a dev dependency.
If you want access to only several icon sets, add @iconify-json/{prefix} dependencies for each icon set (replace {prefix} with icon set prefix).
Plugin can also load icons from Iconify API and cache it, but this could be slow, so better install dependencies mentioned above.
Import icon component from /~iconify/{prefix}/{name}, where:
{prefix}is icon set prefix, such as "mdi"{name}is icon name, such as "home"
See Iconify icon sets for all icons. Select icon and you'll see an option to copy icon name.
Then use that icon as component.
Additionally, instead of /~iconify/ prefix for icon names, you can use:
virtual:iconify/- not supported by webpack/virtual:iconify/- not supported by webpack
You can also change iconify part to anything else by setting namespace option to plugin (see examples in examples directory),
which can be used to run multiple instances of plugin with different options.
<script setup>
import BellIcon from '/~iconify/mdi-light/bell';
</script>
<template>
<BellIcon height="1em" />
</template><script>
import BellIcon from '/~iconify/mdi-light/bell';
</script>
<BellIcon height="1em" />import BellIcon from '/~iconify/mdi-light/bell';
function Test() {
return <BellIcon height="1em" />;
}You can add parameters to component URL:
import BellIcon from '/~iconify/mdi-light/bell?height=1em&compiler=vue';Supported parameters:
square=true- makes icon's viewBox square.widthandheight- sets icon size:height=1em.sizesets bothwidthandheight:size=1em.fallbackoverrides fallback icon name for Safari browser. Set it to an empty string to disable Safari fallback.compileroverrides default compiler for icon.
If you do not specify any of size parameters, generated icon component will accept width and height properties,
which allow you to set size dynamically.
To set a fixed size, you can use width, height or size parameters:
You do not need to set multiple size properties, one is enough.
For example, if you set height=1em, width will be automatically calculated using icon's width/height ratio.
// All examples are identical because icon is square
import BellIcon from '/~iconify/mdi-light/bell?height=1em';
import BellIcon from '/~iconify/mdi-light/bell?width=1em';
import BellIcon from '/~iconify/mdi-light/bell?size=1em';If you set a size parameter, generated component will have hardcoded size and will no longer accept width and height properties.
That means, this will no longer work as expected:
<script setup>
import BellIcon from '/~iconify/mdi-light/bell?height=1em';
</script>
<template>
<!-- Icon will have 1em height because it is set in import URL, property "height" is ignored -->
<BellIcon height="2em" />
</template>To change icon color, change text color.
You can do it in CSS, you can use inline style.
<script setup>
import BellIcon from '/~iconify/mdi-light/bell?size=1em';
</script>
<template>
<BellIcon style="color: red;" />
</template>Possible issues:
Plugin stores generated assets in cache in file system. By default, cache is stored in node_modules/.iconify-unplugin.
If for some reason that directory is not writable, you can set custom cache directory in cacheDir option in plugin.
Iconify Unplugin package is licensed under MIT license.
SPDX-License-Identifier: MIT
© 2025-PRESENT Vjacheslav Trushkin