nuxt-svg-to-icon

2,112
Install
npm install nuxt-svg-to-icon
Latest Version:2.0.0
Vue:3
License:MIT
Last Updated:Aug 18, 2026
Links: GitHub  ·  npm
Maintainer: mokretsovsa

nuxt-svg-to-icon

npm version npm downloads License Nuxt

A Nuxt module that turns your local SVG files into a globally available, fully typed icon component. Drop .svg files into a folder and use them anywhere as <NuxtIcon name="..." /> — with autocompletion for icon names and automatic currentColor theming.

Features

  • 🧩  Global <NuxtIcon> component — auto-registered, no imports needed
  • 🔤  Typed icon names — generates an IconName union type from your SVG files, so name is autocompleted and type-checked
  • 📁  Nested folders — assets/icons/arrows/left.svg becomes name="arrows/left"
  • 🎨  currentColor theming — icons inherit the surrounding text color via fill/stroke; opt out per icon with the filled prop
  • ⚡️  Four loading modes — lazy-load each icon on demand with a shared per-process cache (default), share resolved icons via the Nuxt payload, resolve icons on the client only, or inline all SVGs at build time
  • 🔄  Hot reload — adding, changing, or removing SVGs updates icons and types during nuxt dev

Quick Setup

Install the module in your Nuxt application with one command:

npx nuxt module add nuxt-svg-to-icon

Put your SVG files into assets/icons:

assets/
  icons/
    file.svg
    search.svg
    arrows/
      left.svg

Then use them anywhere in your app:

<template>
  <button>
    <NuxtIcon name="search" /> Search
  </button>

  <!-- nested folders are part of the name -->
  <NuxtIcon name="arrows/left" />

  <!-- keep the SVG's original colors -->
  <NuxtIcon name="file" filled />
</template>

That's it! Icon names are typed — your editor will suggest every icon in the folder. ✨

Configuration

Configure the module under the nuxtSvgToIcon key in nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['nuxt-svg-to-icon'],
  nuxtSvgToIcon: {
    iconsDir: 'assets/icons',
    mode: 'map',
    componentName: 'NuxtIcon',
    componentClassName: 'nuxt-icon',
  },
})
Option Type Default Description
iconsDir string 'assets/icons' Directory (relative to srcDir) that is scanned recursively for .svg files.
mode 'map' | 'useState' | 'client' | 'inline' 'map' Icon loading strategy, see Loading modes.
componentName string 'NuxtIcon' Name of the globally registered component.
componentClassName string 'nuxt-icon' Base CSS class applied to the rendered <span> wrapper.

Component

Props

Prop Type Default Description
name IconName — (required) Icon name: the SVG file path relative to iconsDir, without the .svg extension. Typed as a union of all available icons.
filled boolean false By default the icon's fill (and stroke, when the SVG uses strokes) is forced to currentColor. Set filled to keep the SVG's own colors.

All other attributes (class, style, event listeners, …) fall through to the wrapper <span>.

Rendering & styling

The component renders the raw SVG inside a <span>:

  • The SVG is sized 1em × 1em and vertically aligned with text, so icon size follows font-size.
  • Without filled, a <componentClassName>_fill class forces fill: currentColor; if the SVG contains strokes, <componentClassName>_stroke also forces stroke: currentColor. Color follows the CSS color of the surrounding text.
  • The wrapper carries a data-icon-name attribute for styling or testing hooks.
<span style="color: tomato; font-size: 24px">
  <NuxtIcon name="search" /> <!-- 24px tomato icon -->
</span>

Typed icon names

The module generates a type declaration (#build/nuxt-svg-to-icon-icon-names) with a union of every icon name:

export type IconName = 'file' | 'search' | 'arrows/left'

Passing an unknown name is a type error, and the type regenerates automatically when files in iconsDir change.

Loading modes

map, useState, and client load icons individually via import.meta.glob(..., { query: '?raw' }), so only the icons actually used are ever fetched; they differ in where resolved icons are cached and whether the server resolves them at all. inline skips lazy loading entirely and pre-generates everything at build time.

mode: 'map' (default). Resolved icons are cached in a module-scope Map shared by all component instances. On the server the cache survives across requests, so each icon's file is imported once per process; the payload stays clean — every SVG appears in the HTML response exactly once, as markup. After hydration the client loads each unique icon's chunk once per session (a few KB, cached by the browser). Best default: lightest responses and SSR/SWR-cache friendly.

mode: 'useState'. Resolved icons are cached in Nuxt's useState, which is serialized into the payload. Icons resolved on the server are transferred to the client, so there are no client re-imports after hydration — at the cost of each unique SVG appearing in the response twice (markup + payload). Choose this when hydration speed matters more than response size.

mode: 'client'. Same module-scope Map cache, but the server renders only empty placeholder <span>s and SVGs are resolved on the client after hydration. Server responses carry no icon markup at all, but icons appear late and the empty inline placeholder has no width, so expect layout shift. Suitable for decorative icons below the fold, not for icons that are part of the initial layout.

mode: 'inline'. Every SVG is read at build time and shipped in the public runtime config, so icons render synchronously on server and client with no extra requests. The whole icon set travels with every response regardless of which icons a page uses — fine for small icon sets, wasteful for large ones.

Contribution

Local development
# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with the playground
npm run dev

# Build the playground
npm run dev:build

# Run ESLint
npm run lint

# Run Vitest
npm run test
npm run test:watch

# Release new version
npm run release

Version History

Version Released Vue License
2.0.0 ^3.0 MIT
1.1.0 ^3.0 MIT
1.0.15 ^3.0 MIT
1.0.14 ^3.0 MIT
1.0.13 ^3.0 MIT