unplugin-icons

Import any of Iconify's 200,000+ icons as on-demand components across every major bundler and UI framework.

Tool
npm
v24.0.0
4,959 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
69 /100 Good
Development Activity 48
Maintenance 68
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
68 /100 Good
Architecture 80
Code Quality 55
Innovation 75
Learning Curve 60

unplugin-icons turns the entire Iconify icon universe — around 150 icon sets and 200,000+ icons, logos, and emojis — into components you can import directly by path, like ~icons/mdi/account-box. Built on the unplugin cross-bundler abstraction, it works identically across Vite, Webpack, Rollup, esbuild, and Rspack, and compiles the resolved SVG into native components for React, Vue 3, Svelte, Solid, Preact, Astro, Qwik, Marko, Ember, and plain web components.

Because resolution happens at build time through a virtual-module import, only the icons a project actually references get bundled, keeping output size proportional to real usage rather than to an entire icon font or npm dependency tree. Optional auto-install support fetches missing @iconify-json collections on demand, and a companion resolver plugs into unplugin-vue-components for auto-imported usage without explicit import statements.

What You Get

  • On-demand icon components for ~150 Iconify icon sets (200,000+ icons, logos, and emojis) resolved at import time rather than pre-bundled
  • Uniform behavior across Vite, Webpack, Rollup, esbuild, and Rspack via the shared unplugin abstraction, plus a dedicated Nuxt module
  • Native component output for 10+ UI targets — React, Vue 3, Svelte, Solid, Preact, Astro, Qwik, Marko, Ember, and web components
  • Custom icon collections and an iconCustomizer hook for adjusting size, color, or SVG attributes per icon
  • Optional auto-install of missing @iconify-json/* packages the first time an icon from that set is imported
  • An unplugin-icons/resolver integration for auto-imported icon usage with unplugin-vue-components

Common Use Cases

  • Adding a large, consistent icon set to a Vite or Nuxt app without shipping an icon font or importing every icon manually
  • Building a design system or component library that needs the same icon components available across React, Vue, and Svelte builds
  • Migrating off vite-plugin-icons or a hand-rolled SVG-to-component pipeline onto a maintained, multi-bundler solution
  • Rendering brand/tech logos (via Iconify’s logo collections) inline as styleable components instead of raster images
  • Prototyping across multiple frameworks (via the project’s 13+ example apps) while keeping icon usage syntax identical

Under The Hood

Architecture

unplugin-icons is built on the unplugin package, which provides one plugin definition that targets Vite, Rollup, Webpack, esbuild, and Rspack from a single implementation (src/index.ts), with each bundler entry point (src/vite.ts, src/webpack.ts, src/rollup.ts, src/esbuild.ts, src/rspack.ts, src/nuxt.ts) a thin re-export of that shared instance. The core intercepts virtual ~icons/{collection}/{icon} paths via resolveId/loadInclude/load hooks (src/core/loader.ts: isIconPath, normalizeIconPath, resolveIconsPath), maps each request to a per-framework compiler (src/core/compilers/*.ts — vue3, jsx, svelte, solid, astro, marko, qwik, ember, web-components, raw, none), and fetches the underlying SVG lazily through @iconify/utils’ node loader. Framework detection and defaults (src/core/options.ts resolveOptions) use local-pkg to inspect installed peer packages, so most consumers need zero configuration. This centralizes icon-resolution correctness in one core module while making it straightforward to add a new output framework as an isolated compiler file.

Tech Stack

Written in strict-mode TypeScript (ES2017 target) with unplugin (^2.3.11) as the cross-bundler abstraction, @iconify/utils (^3.1.0) for icon data loading and SVG customization, local-pkg for framework/package detection, @antfu/install-pkg for optional auto-install of icon-set packages, and obug for scoped debug logging. All framework-specific dependencies (Vue’s compiler-sfc, Svelte, @svgr/core, @svgx/core) are optional peer dependencies, so the package stays lean regardless of which frameworks a consumer targets. It builds with tsdown (a Rolldown-based bundler, currently in beta) driven by a custom prebuild script, tests with Vitest, lints with @antfu/eslint-config, and automates releases with bumpp plus dedicated GitHub Actions release workflows.

Code Quality

The repository ships only one dedicated test file (test/idSvg.test.ts, covering SVG id-collision handling), a narrow automated surface for a project of this scope — most real-world coverage instead comes from the 13+ working example apps under examples/ (Vite+Vue3, Vite+React, Next.js, Nuxt 4, SvelteKit, Astro, and more), which exercise the plugin end-to-end per framework but aren’t wired into an automated CI test gate; the visible GitHub Actions workflows cover releases only, not test runs. TypeScript strict mode and strictNullChecks are enabled project-wide, a typecheck script exists, and the code favors small, single-purpose modules (loader.ts, options.ts, svgId.ts) with clearly typed interfaces (ResolvedIconPath, ResolvedOptions) and defensive error handling around environment detection.

API Design The primary interface is a single import-path convention (~icons/{collection}/{icon}) that works identically regardless of bundler or framework, which keeps the mental model small: install the plugin, install (or auto-install) an icon-set package, and import icons like any other component. Per-bundler setup is a one-line plugin registration (e.g. Icons({ compiler: 'vue3' })), and framework auto-detection means many consumers never need to set compiler explicitly. The tradeoff is a large README (1,200+ lines) covering framework-specific caveats — for example Next.js requiring an explicit .jsx extension on icon imports — that a newcomer has to read carefully to avoid subtle per-framework gotchas.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers