Skip to content
4,102
145

unplugin-icons ​

NPM version

Access thousands of icons as components on-demand universally.

Features ​

  • 🌏 Universal
    • 🀹 Any icon sets - ~150 popular sets with over 200,000 icons, logos, emojis, etc. Powered by Iconify.
    • πŸ“¦ Major build tools - Vite, Webpack, Rollup, Nuxt, Rspack, etc. Powered by unplugin.
    • πŸš€ Major frameworks - Vanilla, Web Components, React, Vue 3, Vue 2, Solid, Svelte, and more. Contribute.
    • 🍱 Any combinations of them!
  • ☁️ On-demand - Only bundle the icons you really use, while having all the options.
  • πŸ–¨ SSR / SSG friendly - Ship the icons with your page, no more FOUC.
  • 🌈 Stylable - Change size, color, or even add animations as you would with styles and classes.
  • πŸ“₯ Custom icons - load your custom icons to get universal integrations at ease.
  • πŸ“² Auto Importing - Use icons as components directly in your template.
  • 🦾 TypeScript support.
  • πŸ” Browse Icons

Β Β Β πŸ’‘ Story behind this tool: Journey with Icons Continues - a blog post by AnthonyΒ Β Β 

vite-plugin-icons has been renamed to unplugin-icons, see the migration guide

Usage ​

Import icons names with the convention ~icons/{collection}/{icon} and use them directly as components. Auto importing is also possible.

React ​
jsx
import IconAccessibility from '~icons/carbon/accessibility'
import IconAccountBox from '~icons/mdi/account-box'

function App() {
  return (
    <div>
      <IconAccessibility />
      <IconAccountBox style={{ fontSize: '2em', color: 'red' }} />
    </div>
  )
}
Vue ​
html
<script setup>
import IconAccessibility from '~icons/carbon/accessibility'
import IconAccountBox from '~icons/mdi/account-box'
</script>

<template>
  <icon-accessibility/>
  <icon-account-box style="font-size: 2em; color: red"/>
</template>

Install ​

Plugin ​

bash
npm i -D unplugin-icons

Icons Data ​

We use Iconify as the icons data source (supports 100+ iconsets).

You have two ways to install them:

Install Full Collection ​
bash
npm i -D @iconify/json

@iconify/json (~120MB) includes all the iconsets from Iconify so you can install once and use any of them as you want (only the icons you actually use will be bundle into the production build).

Install by Icon Set ​

If you only want to use a few of the icon sets and don't want to download the entire collection, you can also install them individually with @iconify-json/[collection-id]. For example, to install Material Design Icons, you can do:

bash
npm i -D @iconify-json/mdi

To boost your workflow, it's also possible to let unplugin-icons handle that installation by enabling the autoInstall option.

ts
Icons({
  // experimental
  autoInstall: true,
})

It will install the icon set when you import them. The right package manager will be auto-detected (npm, yarn or pnpm).

Examples ​

You can play online with the examples in this repo in StackBlitz, see playgrounds page.

Fork any of the online examples and reproduce the issue you're facing, then share the link with us.

Configuration ​

Build Tools ​
Vite
ts
// vite.config.ts
import Icons from 'unplugin-icons/vite'

export default defineConfig({
  plugins: [
    Icons({ /* options */ }),
  ],
})
Rollup
ts
// rollup.config.js
import Icons from 'unplugin-icons/rollup'

export default {
  plugins: [
    Icons({ /* options */ }),
  ],
}
Webpack
ts
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('unplugin-icons/webpack').default({ /* options */ }),
  ],
}
Nuxt

Nuxt 2 and Nuxt Bridge

ts
// nuxt.config.js
export default {
  buildModules: [
    ['unplugin-icons/nuxt', { /* options */ }],
  ],
}

Nuxt 3

ts
// nuxt.config.js
export default defineNuxtConfig({
  modules: [
    ['unplugin-icons/nuxt', { /* options */ }]
  ],
})

Or work with unplugin-vue-components resolvers

ts
import ViteComponents from 'unplugin-vue-components/vite'
import IconsResolver from 'unplugin-icons/resolver'

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    'unplugin-icons/nuxt',
  ],
  vite: {
    plugins: [
      ViteComponents({
        resolvers: [
          IconsResolver({/* options */}),
        ],
      }),
    ],
  },
})

See the Nuxt example for a working example project.

Rspack
ts
import Icons from 'unplugin-icons/rspack'

// rspack.config.mjs
export default defineConfig({
  plugins: [
    // ...
    Icons({/* options */}),
  ]
})
Vue CLI
ts
// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      require('unplugin-icons/webpack').default({ /* options */ }),
    ],
  },
}

You can also rename the Vue configuration file to vue.config.mjs and use static import syntax (you should use latest @vue/cli-service ^5.0.8):

ts
// vue.config.mjs
import Icons from 'unplugin-icons/webpack'

export default {
  configureWebpack: {
    plugins: [
      Icons({ /* options */ }),
    ],
  },
}
SvelteKit

The unplugin-icons plugin should be configured in the vite.config.js configuration file:

ts
// vite.config.js
import { defineConfig } from 'vite'
import { sveltekit } from '@sveltejs/kit/vite'
import Icons from 'unplugin-icons/vite'

export default defineConfig({
  plugins: [
    sveltekit(),
    Icons({
      compiler: 'svelte',
    })
  ]
})

Check instructions in the Frameworks -> Svelte section below if you faced module import errors.

See the SvelteKit example for a working example project.

Svelte + Vite

Svelte support requires the @sveltejs/vite-plugin-svelte plugin:

shell
npm i -D @sveltejs/vite-plugin-svelte

The unplugin-icons plugin should be configured in the vite.config.js configuration file:

ts
// vite.config.js
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import Icons from 'unplugin-icons/vite'

export default defineConfig({
  plugins: [
    svelte(),
    Icons({
      compiler: 'svelte',
    }),
  ],
})

Check instructions in the Frameworks -> Svelte section below if you faced module import errors.

See the Svelte + Vite example for a working example project.

Next.js

The unplugin-icons plugin should be configured on next.config.js configuration file:

ts
// next.config.js
/** @type {import('next').NextConfig} */
module.exports = {
  reactStrictMode: true,
  webpack(config) {
    config.plugins.push(
      require('unplugin-icons/webpack').default({
        compiler: 'jsx',
        jsx: 'react'
      })
    )

    return config
  },
}

You can also rename the Next configuration file to next.config.mjs and use static import syntax:

ts
// next.config.mjs
import Icons from 'unplugin-icons/webpack'

/** @type {import('next').NextConfig} */
export default {
  reactStrictMode: true,
  webpack(config) {
    config.plugins.push(
      Icons({
        compiler: 'jsx',
        jsx: 'react'
      })
    )

    return config
  }
}

Check instructions in the Frameworks -> React section below if you faced module import errors.

⚠️ Warning: to import an icon is necessary to explicitly add the .jsx extension to the import path, so that Next.js knows how to load it, by example:

ts
import IconArrowRight from '~icons/dashicons/arrow-right.jsx';
                                                     // ^-- write `.jsx` to avoid
                                                     // https://github.com/antfu/unplugin-icons/issues/103
// ...some code later
<IconArrowRight />

See the Next.js example for a working example project.

esbuild
ts
// esbuild.config.js
import { build } from 'esbuild'
import Icons from 'unplugin-icons/esbuild'

build({
  /* ... */
  plugins: [
    Icons({
      /* options */
    }),
  ],
})
Astro
ts
// astro.config.mjs
import { defineConfig } from 'astro/config'
import Icons from 'unplugin-icons/vite'

// https://astro.build/config
export default defineConfig({
  vite: {
    plugins: [
      Icons({
        compiler: 'astro',
      }),
    ],
  },
})

See the Astro example for a working example project.

Astro + Vue

Required @astrojs/vue installed.

ts
// astro.config.mjs
import { defineConfig } from 'astro/config'
import Vue from '@astrojs/vue'
import Icons from 'unplugin-icons/vite'

// https://astro.build/config
export default defineConfig({
  integrations: [
    Vue(),
  ],
  vite: {
    plugins: [
      Icons({
        compiler: 'vue3',
      }),
    ],
  },
})

See the Astro + Vue example for a working example project.

Frameworks ​
Vue 3 / Vue 2.7+

Vue 3 / Vue 2.7+ support requires peer dependency @vue/compiler-sfc:

bash
npm i -D @vue/compiler-sfc
ts
Icons({ compiler: 'vue3' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/vue",
    ]
  }
}

See the Vue 3 example for a working example project.

Vue 2 (only for versions < 2.7)

Vue 2 support requires peer dependency vue-template-compiler:

bash
npm i -D vue-template-compiler
ts
Icons({ compiler: 'vue2' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/vue",
    ]
  }
}

See the Vue 2 example for a working example project.

React

JSX support requires peer dependency @svgr/core and its plugin @svgr/plugin-jsx:

bash
npm i -D @svgr/core @svgr/plugin-jsx
ts
Icons({ compiler: 'jsx', jsx: 'react' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/react",
    ]
  }
}

See the React example for a working example project.

Preact

JSX support requires peer dependency @svgr/core and its plugin @svgr/plugin-jsx:

bash
npm i -D @svgr/core @svgr/plugin-jsx
ts
Icons({ compiler: 'jsx', jsx: 'preact' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/preact",
    ]
  }
}

See the Preact example for a working example project.

Solid
ts
Icons({ compiler: 'solid' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/solid",
    ]
  }
}

See the Solid example for a working example project.

Svelte
ts
Icons({ compiler: 'svelte' })

Type Declarations

For SvelteKit, in the src/app.d.ts file:

ts
import 'unplugin-icons/types/svelte'

For Svelte + Vite, in the src/vite-env.d.ts file:

js
/// <reference types="svelte" />
/// <reference types="vite/client" />
/// <reference types="unplugin-icons/types/svelte" />

If you're still using Svelte 4, replace the reference to use Svelte 4:

js
/// <reference types="svelte" />
/// <reference types="vite/client" />
/// <reference types="unplugin-icons/types/svelte4" />

If you're still using Svelte 3, replace the reference to use Svelte 3:

js
/// <reference types="svelte" />
/// <reference types="vite/client" />
/// <reference types="unplugin-icons/types/svelte3" />

See the Svelte example for a working example project.

Astro

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/astro",
    ]
  }
}

See the Astro example for a working example project.

Astro + Vue

Only the Vue type declarations are required:

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/vue"
    ]
  }
}

See the Astro + Vue example for a working example project.

Qwik

Qwik support requires peer dependency @svgx/core:

bash
npm i -D @svgx/core
ts
Icons({ compiler: 'qwik' })

Alternatively, you can use jsx compiler, requires peer dependency @svgr/core and its plugin @svgr/plugin-jsx:

bash
npm i -D @svgr/core @svgr/plugin-jsx
ts
Icons({ compiler: 'jsx', jsx: 'qwik' })

Type Declarations

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "unplugin-icons/types/qwik",
    ]
  }
}

See the Qwik example for a working example project.

Use RAW compiler from query params ​

From v0.13.2 you can also use raw compiler to access the svg icon and use it on your html templates, just add raw to the icon query param.

For example, using vue3:

vue
<script setup lang='ts'>
import RawMdiAlarmOff from '~icons/mdi/alarm-off?raw&width=4em&height=4em'
import RawMdiAlarmOff2 from '~icons/mdi/alarm-off?raw&width=1em&height=1em'
</script>

<template>
  <!-- raw example -->
  <pre>
    import RawMdiAlarmOff from '~icons/mdi/alarm-off?raw&width=4em&height=4em'
    {{ RawMdiAlarmOff }}
    import RawMdiAlarmOff2 from '~icons/mdi/alarm-off?raw&width=1em&height=1em'
    {{ RawMdiAlarmOff2 }}
  </pre>
  <!-- svg example -->
  <span v-html="RawMdiAlarmOff" />
  <span v-html="RawMdiAlarmOff2" />
</template>

Custom Icons ​

From v0.11, you can now load your own icons!

From v0.13 you can also provide a transform callback to FileSystemIconLoader.

ts
import { promises as fs } from 'node:fs'

// loader helpers
import { FileSystemIconLoader } from 'unplugin-icons/loaders'

Icons({
  customCollections: {
    // key as the collection name
    'my-icons': {
      account: '<svg><!-- ... --></svg>',
      // load your custom icon lazily
      settings: () => fs.readFile('./path/to/my-icon.svg', 'utf-8'),
      /* ... */
    },
    'my-other-icons': async (iconName) => {
      // your custom loader here. Do whatever you want.
      // for example, fetch from a remote server:
      return await fetch(`https://example.com/icons/${iconName}.svg`).then(res => res.text())
    },
    // a helper to load icons from the file system
    // files under `./assets/icons` with `.svg` extension will be loaded as it's file name
    // you can also provide a transform callback to change each icon (optional)
    'my-yet-other-icons': FileSystemIconLoader(
      './assets/icons',
      svg => svg.replace(/^<svg /, '<svg fill="currentColor" '),
    ),
  },
})

Then use as

ts
import IconAccount from '~icons/my-icons/account'
import IconFoo from '~icons/my-other-icons/foo'
import IconBar from '~icons/my-yet-other-icons/bar'

πŸ’‘ SVG Authoring Tips:

  • To make your icons color adaptable, set fill="currentColor" or stroke="currentColor" in your SVG.
  • Leave the height and width unspecified, we will set them for you.

Use with Resolver ​

When using resolvers for auto-importing, you will need to tell it your custom collection names:

ts
IconResolver({
  customCollections: [
    'my-icons',
    'my-other-icons',
    'my-yet-other-icons',
  ],
})

See the Vue 3 + Vite example.

Use Custom External Collection Packages ​

From version v0.18.3 you can use other packages to load icons from others authors.

WARNING: external packages must include icons.json file with the icons data in IconifyJSON format, which can be exported with Iconify Tools. Check Exporting icon set as JSON package for more details.

For example, you can use an-awesome-collection or @my-awesome-collections/some-collection to load your custom or third party icons:

ts
// loader helpers
import { ExternalPackageIconLoader } from 'unplugin-icons/loaders'

Icons({ customCollections: ExternalPackageIconLoader('my-awesome-collection') })

When using with resolvers for auto-importing, remember you will need to tell it your custom collection names:

ts
IconResolver({
  customCollections: [
    'my-awesome-collection',
  ],
})

You can also combine it with FileSystemIconLoader or with other custom icon loaders:

ts
// loader helpers
import { ExternalPackageIconLoader, FileSystemIconLoader } from 'unplugin-icons/loaders'

Icons({
  customCollections: {
    ...ExternalPackageIconLoader('an-awesome-collection'),
    ...ExternalPackageIconLoader('@my-awesome-collections/some-collection'),
    ...ExternalPackageIconLoader('@my-awesome-collections/some-other-collection'),
    'my-yet-other-icons': FileSystemIconLoader(
      './assets/icons',
      svg => svg.replace(/^<svg /, '<svg fill="currentColor" '),
    ),
  },
})

See the Vue 3 + Vite example.

Icon customizer ​

From v0.13 you can also customize each icon using iconCustomizer configuration option or using query params when importing them.

The query param will take precedence over iconCustomizer and iconCustomizer over configuration.

The iconCustomizer and query params will be applied to any collection, that is, for each icon from custom loader, inlined on customCollections or from @iconify.

For example, you can configure iconCustomizer to change all icons for a collection or individual icons on a collection:

ts
import { promises as fs } from 'node:fs'

// loader helpers
import { FileSystemIconLoader } from 'unplugin-icons/loaders'

Icons({
  customCollections: {
    // key as the collection name
    'my-icons': {
      account: '<svg><!-- ... --></svg>',
      // load your custom icon lazily
      settings: () => fs.readFile('./path/to/my-icon.svg', 'utf-8'),
      /* ... */
    },
    'my-other-icons': async (iconName) => {
      // your custom loader here. Do whatever you want.
      // for example, fetch from a remote server:
      return await fetch(`https://example.com/icons/${iconName}.svg`).then(res => res.text())
    },
    // a helper to load icons from the file system
    // files under `./assets/icons` with `.svg` extension will be loaded as it's file name
    // you can also provide a transform callback to change each icon (optional)
    'my-yet-other-icons': FileSystemIconLoader(
      './assets/icons',
      svg => svg.replace(/^<svg /, '<svg fill="currentColor" '),
    ),
  },
  iconCustomizer(collection, icon, props) {
    // customize all icons in this collection
    if (collection === 'my-other-icons') {
      props.width = '4em'
      props.height = '4em'
    }
    // customize this icon in this collection
    if (collection === 'my-icons' && icon === 'account') {
      props.width = '6em'
      props.height = '6em'
    }
    // customize this @iconify icon in this collection
    if (collection === 'mdi' && icon === 'account') {
      props.width = '2em'
      props.height = '2em'
    }
  },
})

or you can use query params to apply to individual icons:

vue
<script setup lang='ts'>
import MdiAlarmOff from 'virtual:icons/mdi/alarm-off?width=4em&height=4em'
import MdiAlarmOff2 from 'virtual:icons/mdi/alarm-off?width=1em&height=1em'
</script>

<template>
  <!-- width=4em and height=4em -->
  <mdi-alarm-off />
  <!-- width=4em and height=4em -->
  <MdiAlarmOff />
  <!-- width=1em and height=1em -->
  <MdiAlarmOff2 />
</template>

See src/App.vue component and vite.config.ts configuration on vite-vue3 example project.

Global Custom Icon Transformation ​

From version 0.14.2, when loading your custom icons, you can transform them, for example adding fill attribute with currentColor:

ts
Icons({
  customCollections: {
    // key as the collection name
    'my-icons': {
      account: '<svg><!-- ... --></svg>',
      /* ... */
    },
  },
  transform(svg, collection, icon) {
    // apply fill to this icon on this collection
    if (collection === 'my-icons' && icon === 'account')
      return svg.replace(/^<svg /, '<svg fill="currentColor" ')

    return svg
  },
})

Advanced Custom Icon Set Cleanup ​

When using this plugin with your custom icons, consider using a cleanup process similar to that done by Iconify for any icons sets. All the tools you need are available in Iconify Tools.

You can check this repo, using unplugin-icons on a SvelteKit project: https://github.com/iconify/tools/tree/main/%40iconify-demo/unplugin-svelte.

Read Cleaning up icons article from Iconify for more details.

Migrate from vite-plugin-icons ​

package.json

diff
{
  "devDependencies": {
-   "vite-plugin-icons": "*",
+   "unplugin-icons": "^0.7.0",
  }
}

vite.config.json

diff
import Components from 'unplugin-vue-components/vite'
- import Icons, { ViteIconsResolver } from 'vite-plugin-icons'
+ import Icons from 'unplugin-icons/vite'
+ import IconsResolver from 'unplugin-icons/resolver'

export default {
  plugins: [
    Vue(),
    Components({
      resolvers: [
        IconsResolver()
      ],
    }),
    Icons(),
  ],
}

* - imports usage

diff
- import IconComponent from 'virtual:vite-icons/collection/name'
+ import IconComponent from '~icons/collection/name'

You can still use virtual:icons prefix in Vite if you prefer, but it's not yet supported in Webpack, we are unifying it as a workaround in the docs.

Options ​

You can set default styling for all icons. The following config shows the default values of each option:

ts
Icons({
  scale: 1.2, // Scale of icons against 1em
  defaultStyle: '', // Style apply to icons
  defaultClass: '', // Class names apply to icons
  compiler: null, // 'vue2', 'vue3', 'jsx'
  jsx: 'react', // 'react' or 'preact'
})

Auto Importing ​

Vue 2 & 3

Use with unplugin-vue-components

For example in Vite:

js
// vite.config.js
import Vue from '@vitejs/plugin-vue'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'

export default {
  plugins: [
    Vue(),
    Components({
      resolvers: [
        IconsResolver(),
      ],
    }),
    Icons(),
  ],
}

Then you can use any icons as you want without explicit importing. Only the used icons will be bundled.

html
<template>
  <i-carbon-accessibility/>
  <i-mdi-account-box style="font-size: 2em; color: red"/>
</template>
React & Solid

Use with unplugin-auto-import

For example in Vite:

js
// vite.config.js
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import AutoImport from 'unplugin-auto-import/vite'

export default {
  plugins: [
    /* ... */
    AutoImport({
      resolvers: [
        IconsResolver({
          prefix: 'Icon',
          extension: 'jsx',
        }),
      ],
    }),
    Icons({
      compiler: 'jsx', // or 'solid'
    }),
  ],
}

Then you can use any icons with the prefix Icon as you want without explicit importing. Type declarations will be generated on the fly.

js
export function Component() {
  return (
    <div>
      <IconCarbonApps />
      <IconMdiAccountBox style="font-size: 2em; color: red" />
    </div>
  )
}

Name Conversion ​

When using component resolver, you have to follow the name conversion for icons to be properly inferred.

{prefix}-{collection}-{icon}

The collection field follows Iconify's collection IDs.

By default, the prefix is set to i while you can customize via config

ts
IconsResolver({
  prefix: 'icon', // <--
})
html
<template>
  <icon-mdi-account />
</template>

Non-prefix mode is also supported

ts
IconsResolver({
  prefix: false, // <--
  // this is optional, default enabling all the collections supported by Iconify
  enabledCollections: ['mdi'],
})
vue
<template>
  <mdi-account />
</template>

Collection Aliases ​

When using component resolver, you have to use the name of the collection that can be long or redundant: for example, when using icon-park collection you need to use it like this <icon-icon-park-abnormal />.

You can add an alias for any collection to the IconResolver plugin:

ts
IconsResolver({
  alias: {
    park: 'icon-park',
    fas: 'fa-solid',
    // ...
  }
})

You can use the alias or the collection name, the plugin will resolve both.

Following with the example and configuring the plugin with previous alias entry, you can now use <icon-park-abnormal /> or <icon-icon-park-abnormal />.

Sponsors ​

This project is part of my Sponsor Program

License ​

MIT License Β© 2020-PRESENT Anthony Fu

Released under the MIT License.