iconify-static Svelte Themes

Iconify Static

Use Iconify without the external CDN

iconify-static

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/

Motivation

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:

  • Their CDN goes offline.
  • You are making an offline or offline-first app (e.g. a mobile app via Capacitor).

This library aims to address this, by providing an easy to use replacement that downloads and bundles the icons that your app uses.

Features

  • Only downloads the icons you actually use.
  • Icons stored locally in your assets directory; no runtime dependency on Iconify CDN.
  • Automatic icon detection from source code.
  • Vite plugin downloads new icons at build time.
  • Works with Svelte components and vanilla web components.

Installation

Step 1: Install the package

npm install iconify-static

Step 2: Configure Vite

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()
  ]
});

Step 3: Use icons in your components

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>

Step 4: Build or run via Vite

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/.

Usage Examples

Svelte Component

<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" />

Web Component

<!-- 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>

Props

Svelte Component Props

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

Web Component Attributes

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"

Plugin Configuration

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'],
})

Icon Detection

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 -->

Detecting Icons in Constants/Variables

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'];

Preserving Unused Icons

By default, icons not found in source code are deleted. To preserve all icons:

iconifyStatic({
  cleanup: false
})

Deploying to a Subpath (GitHub Pages, etc.)

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()],
});

Limitations

scanPrefixes limitations

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:

  1. Ensure all possible icons are referenced as string literals somewhere in code
  2. Use cleanup: false and manually manage icons in static/_icons/

False positives

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.

Supported Icon Sets

Any icon set available on Iconify works:

  • mdi - Material Design Icons
  • carbon - IBM Carbon
  • lucide - Lucide
  • tabler - Tabler Icons
  • ph - Phosphor Icons
  • fluent - Fluent UI Icons
  • And many more...

Contributing & Raising Issues

Please 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.

Support

Please make sure to support the Iconify team and the designers who make the icons you use!

License

MIT

Top categories

Loading Svelte Themes