Vue and Nuxt setup
Set svgworm up in a Vue or Nuxt app in three steps. The Icon component is a plain .vue file that init writes into your project. It needs no extra package, and it renders the same markup as the React Icon. With server rendering, icons show before any JavaScript runs.
Requires Node ^22.20 || >=24.11 and Vue 3.5 (Nuxt 4 runs on it).
Steps#
-
Install and set up:
pnpm add -D svgworm && pnpm svgworm init # npm: npm install -D svgworm && npx svgworm init # yarn: yarn add -D svgworm && yarn svgworm initinitsees thevueornuxtdependency and does the setup for you:- Files: writes
svgworm.config.json, thepredev/prebuildscripts and the component. Then it builds once. - Where the component goes:
- Nuxt 4:
app/components/Icon.vue. - Nuxt 3, or Nuxt 4 that keeps the Nuxt 3 layout (no
app/folder, orapp.vueat the root):components/Icon.vue. - With
@nuxt/iconor Nuxt UI, the file isSvgIcon.vueinstead, rendered as<SvgIcon>, because those modules already register<Icon>. - Otherwise:
src/components/Icon.vue.
- Nuxt 4:
- Sample icon: if
icons/is missing or empty, it addsicons/svgworm.svgso the first build works. - Flags: with
--yesit asks nothing. Use--framework vuewhen the project has novuedependency yet.
See the CLI reference for every flag.
- Files: writes
-
Put your SVG files in
icons/(delete the sample) and build:pnpm svgwormThis writes the sprite to
public/icons/and the manifest and types tosvgworm/. Vite and Nuxt servepublic/as is. While you work, runsvgworm watchnext to the dev server to rebuild on each change. -
Use it in any component:
<script setup lang="ts"> // Nuxt auto-imports it: skip this line there. import Icon from "../components/Icon.vue"; </script> <template> <nav> <Icon name="home" /> <Icon name="brand/sunset" :width="32" :height="32" /> <Icon name="home" title="Go home" class="nav-icon" /> </nav> </template>- Names come from the file paths:
homeisicons/home.svgandbrand/sunsetisicons/brand/sunset.svg, lower-cased with-between words. - Type-checked:
nameis typed from the generatedIconName, so a typo failsvue-tsc(andnuxi typecheck). - Decorative by default: the icon is
aria-hiddenunless you passtitleorlabel. - Attributes pass through:
class,style(a string, an object or an array, as in any Vue template),id,data-*andaria-*land on the rendered element.
- Names come from the file paths:
@nuxt/icon (and Nuxt UI, which uses it) registers a global <Icon>. When either is a dependency, init names the file SvgIcon.vue, which Nuxt auto-imports as <SvgIcon>. If you add the module later, rename one of the two: its icon.componentName option (for example NuxtIcon), or your file.
Icon.vue is your file, and init never overwrites it. To refresh it after upgrading svgworm, delete it and run svgworm init again.
Set up by hand#
Without init, run the CLI before dev and build yourself:
{ "scripts": { "predev": "svgworm", "prebuild": "svgworm" } }
Yarn 2+ never runs pre scripts. With it, put the command in front of the scripts instead, for example "dev": "svgworm && nuxt dev". Then copy the component from svgworm init --framework vue in a scratch folder.
With Vite, the optional svgworm/vite plugin can rebuild icons inside vite dev. It does not depend on React. See the plugin section of the Vite setup.
base#
Sprites on a CDN#
init --cdn-url is not supported for Vue yet: crossOrigin "inject" needs a loader <script> in the page, and init does not write one for Vue (ADR-0034). Icon.vue already renders the in-page references that mode needs. Until it is, serve the sprites from your own origin.
Cache for a year#
The file names are content-hashed, so a long cache is safe. Send Cache-Control: public, max-age=31536000, immutable for /icons/* from your host, as in the Astro setup.
What to commit and CI#
Commit public/icons/ and svgworm/ and run svgworm check in CI, before the build. It fails when someone changed an icon and forgot to rebuild. Or ignore both folders and rely on the predev and prebuild scripts: then anything that type-checks before the build must run svgworm first.
pnpm svgworm check
pnpm build
How it is checked#
A conformance test compiles the generated Icon.vue for the server and checks that it renders the same markup as the React Icon from the same manifest, for every delivery. vue-tsc checks that an unknown name is a type error.
Next steps#
- Icon component: every prop, the markup per delivery, sizing and coloring with CSS.
- How it works: the sprite, the stack, delivery forms, the manifest and determinism.
- CLI reference: every command, flag and exit code.
- Troubleshooting: blank icons, 404s, wrong colors, collisions,
checkin CI. - Using Svelte? Read the Svelte setup.