Offline-first Iconify icons for Svelte and web components. Icons are downloaded at build time and served from your static assets, instead of an external CDN.
This project aims to be a drop-in replacement for the existing Iconify library.
Demo: https://drbscl.github.io/iconify-static/
Iconify is a great way to add icons to your webapp, but the official library loads SVGs clientside via their CDN. This can be a limitation if:
This library aims to address this, by providing an easy to use replacement that downloads and bundles the icons that your app uses.
npm install iconify-static
Add the plugin to your vite.config.ts:
import { sveltekit } from '@sveltejs/kit/vite';
import { iconifyStatic } from 'iconify-static/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(), // Only required for sveltekit; you don't need this if you're using web components
iconifyStatic()
]
});
Svelte component:
<script>
import { Icon } from 'iconify-static';
</script>
<Icon icon="mdi:home" />
Web component:
<script>
import { registerIconifyStatic } from 'iconify-static';
registerIconifyStatic();
</script>
<iconify-icon icon="mdi:home"></iconify-icon>
Build or run with your usual command, e.g.
npm run dev
npm run build
The plugin automatically detects icons used in your code and downloads them to static/_icons/.
<script>
import { Icon } from 'iconify-static';
</script>
<!-- Basic usage -->
<Icon icon="mdi:home" />
<!-- With size -->
<Icon icon="mdi:star" width="32" />
<Icon icon="mdi:star" width="2em" />
<!-- With color -->
<Icon icon="mdi:heart" color="red" />
<Icon icon="mdi:heart" color="#ff6600" />
<!-- Inline with text -->
<p>Click the <Icon icon="mdi:menu" inline /> icon to...</p>
<!-- Transformations -->
<Icon icon="mdi:arrow-right" hFlip />
<Icon icon="mdi:arrow-right" vFlip />
<Icon icon="mdi:arrow-right" rotate={1} />
<Icon icon="mdi:arrow-right" rotate="45deg" />
<!-- Multiple icon sets -->
<Icon icon="ph:house" />
<Icon icon="carbon:home" />
<Icon icon="lucide:home" />
<Icon icon="tabler:home" />
<!-- Basic usage -->
<iconify-icon icon="mdi:home"></iconify-icon>
<!-- With size -->
<iconify-icon icon="mdi:star" width="32"></iconify-icon>
<!-- With color -->
<iconify-icon icon="mdi:heart" color="red"></iconify-icon>
<!-- Inline with text -->
<p>Click the <iconify-icon icon="mdi:menu" inline></iconify-icon> icon to...</p>
<!-- Transformations -->
<iconify-icon icon="mdi:arrow-right" flip="horizontal"></iconify-icon>
<iconify-icon icon="mdi:arrow-right" rotate="1"></iconify-icon>
| Prop | Type | Default | Description |
|---|---|---|---|
icon |
string |
required | Icon name in "prefix:name" format (e.g., "mdi:home") |
width |
string | number |
"1em" |
Icon width (number or CSS unit) |
height |
string | number |
width |
Icon height (defaults to width) |
color |
string |
- | Icon color (any CSS color value) |
inline |
boolean |
false |
Align icon with text baseline |
hFlip |
boolean |
false |
Flip icon horizontally |
vFlip |
boolean |
false |
Flip icon vertically |
flip |
string |
- | "horizontal", "vertical", or "horizontal,vertical" |
rotate |
number | string |
- | Rotation: 0-3 for 90deg increments, or CSS angle like "45deg" |
onLoad |
function |
- | Callback when icon SVG loads |
| Attribute | Type | Default | Description |
|---|---|---|---|
icon |
string |
required | Icon name in "prefix:name" format |
width |
string |
"1em" |
Icon width |
height |
string |
width |
Icon height |
color |
string |
- | Icon color |
inline |
(boolean attr) | - | Align icon with text baseline |
flip |
string |
- | "horizontal", "vertical", or "horizontal,vertical" |
rotate |
string |
- | Rotation: "0"-"3" for 90deg increments, or "45deg" |
iconifyStatic({
// Directory where icons are saved (default: 'static/_icons')
iconsDir: 'static/_icons',
// Directory to scan for icon usage (default: 'src')
sourceDir: 'src',
// Remove unused icons from iconsDir (default: true)
cleanup: true,
// Log download/removal activity (default: false)
verbose: false,
// Scan for icons in all strings across your files with these prefixes (default: [])
scanPrefixes: ['mdi', 'carbon'],
})
By default, the plugin detects icons used in the icon prop:
<Icon icon="mdi:home" /> <!-- Detected -->
<Icon icon='carbon:search' /> <!-- Detected -->
<Icon icon={`lucide:check`} /> <!-- Detected -->
For icons stored in constants or variables, use the scanPrefixes option:
// vite.config.ts
iconifyStatic({
scanPrefixes: ['mdi', 'carbon']
})
This scans for any string matching "{prefix}:{name}" anywhere in your code:
// All of these are now detected when scanPrefixes includes 'mdi':
const HOME_ICON = 'mdi:home';
const icons = { settings: 'mdi:cog', user: 'mdi:account' };
const list = ['mdi:star', 'mdi:heart'];
By default, icons not found in source code are deleted. To preserve all icons:
iconifyStatic({
cleanup: false
})
When deploying to a subpath (e.g., https://username.github.io/repo-name/), configure Vite's base option so icons are fetched from the correct URL.
SvelteKit (svelte.config.js):
const dev = process.argv.includes("dev");
export default {
kit: {
paths: {
base: dev ? "" : "/repo-name",
},
},
};
Plain Vite (vite.config.ts):
export default defineConfig({
base: process.env.NODE_ENV === "production" ? "/repo-name" : "/",
plugins: [iconifyStatic()],
});
The scanPrefixes option only detects string literals. These patterns are not detected:
// NOT detected - runtime concatenation
const prefix = 'mdi';
const icon = prefix + ':home';
// NOT detected - template literal with variable
const name = 'home';
const icon = `mdi:${name}`;
// NOT detected - dynamic from API/database
const icon = await fetchIconName();
For truly dynamic icons, either:
cleanup: false and manually manage icons in static/_icons/scanPrefixes may detect strings that look like icons but aren't:
// This would be detected if scanPrefixes includes 'mdi'
const notAnIcon = 'mdi:this-is-not-real';
This results in a build error if the icon doesn't exist.
Any icon set available on Iconify works:
mdi - Material Design Iconscarbon - IBM Carbonlucide - Lucidetabler - Tabler Iconsph - Phosphor Iconsfluent - Fluent UI IconsPlease feel free to raise issues for bugs or feature requests, but refrain from using AI to write them.
This project aims to be a drop-in replacement for Iconify's Svelte components, but may not be perfect; any differences are bugs, and detailed reports are appreciated.
PRs for fixes and improvements are welcomed, but I recommend raising an issue first if possible. AI generated changes may be accepted, but please make sure to validate, test, and check them for quality before raising a PR.
Please make sure to support the Iconify team and the designers who make the icons you use!
MIT