Laravel Mix SVG Vue
Extension to inline SVG files with Vue.js and optimize them automatically with SVGO.
[!IMPORTANT] As of v0.5.0 this extension supports Vue 3 only. Vue 2 reached end of life on December 31, 2023, so its support has been dropped.
Still on Vue 2? Stay on the last release that supports it:
npm install laravel-mix-svg-vue@^0.4See the release notes for details.
Installation
# npm
npm install laravel-mix-svg-vue
# pnpm
pnpm add laravel-mix-svg-vue
Next require the extension inside your Laravel Mix config and call svgVue() in your pipeline:
// webpack.mix.js
const mix = require('laravel-mix');
require('laravel-mix-svg-vue');
mix.js('resources/js/app.js', 'public/js')
// .vue() // only necessary if you are using mix v6
.svgVue();
The last step is to import and register the Vue component:
// e.g. app.js
import { createApp } from 'vue';
import SvgVue from 'svg-vue3';
const app = createApp({});
app.use(SvgVue);
app.mount('#app');
Usage
To display your SVG files, all you need to do is pass the filename (and path if placed inside a subdirectory) to the Vue component:
<!-- resources/svg/avatar.svg -->
<svg-vue icon="avatar"></svg-vue>
<!-- resources/svg/fontawesome/check.svg -->
<svg-vue icon="fontawesome/check"></svg-vue>
<!-- you can also use a "dot" notation as path -->
<svg-vue icon="fontawesome.check"></svg-vue>
The icon name is the path relative to your svgPath without the .svg extension. If an icon cannot be found, the component logs a descriptive error to the browser console and renders an empty <svg> instead of throwing, so a single mistyped name won't break the rest of your app.
Options
Default options
If nothing is passed to the extension inside your Laravel Mix config, the following options will be used:
{
svgPath: 'resources/svg',
extract: false,
svgoSettings: [
{ removeTitle: true },
{ removeViewBox: false },
{ removeDimensions: true }
]
}
Option details
svgPath
The path to your SVG files relative to the Laravel Mix config.
extract
If you wish to extract the SVG's to a separate file instead of including them in your main app.js, you can set this option to true. This will create a svg.js file which then needs to be loaded in your HTML. Make sure to load app.js before svg.js:
<script src="{{ mix('js/app.js') }}"></script>
<script src="{{ mix('js/svg.js') }}"></script>
svgoSettings
Plugin configuration passed to SVGO. See here for a list of available settings.
Options overview
| Option | Type | Default | Description |
|---|---|---|---|
svgPath |
String | resources/svg |
Path to your SVG files |
extract |
Boolean | false |
Separate the SVG's from your main bundle |
svgoSettings |
Array | [{ removeTitle: true }, { removeViewBox: false }, { removeDimensions: true }] |
SVGO settings |
Toggling or rendering icons inside lists
Not really related to this extension, but when more than one <svg-vue> icon is rendered inside a conditional state with v-if or v-for, a key attribute should be used to tell Vue that an element needs to change when any condition changes.
While in most cases the cost for toggling elements with v-show should be preferred (also no need for a key attribute then), a simple example when toggling an icon with v-if inside a button could look like this:
<button v-if="active" key="active-btn">
<svg-vue icon="active-icon" class="..."></svg-vue>
<span>Active</span>
</button>
<button v-if="inactive" key="inactive-btn">
<svg-vue icon="inactive-icon" class="..."></svg-vue>
<span>Inactive</span>
</button>
Rendering lists could be handled like this:
<ul>
<li v-for="item in items" :key="item.id">
<p>{{ item.title }}</p>
<svg-vue :icon="item.icon" class="..."></svg-vue>
</li>
</ul>
Just remember the key has to be unique. More examples for this can be found in the Vue documentation.
When toggling between elements that have the same tag name, you must tell Vue that they are distinct by giving them unique key attributes. Otherwise Vue’s compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, it’s considered good practice to always key multiple items within a component.
Testing
The test suite runs against Vue 3 (svg-vue3). The component lives in this repository as a pnpm workspace package under packages/, so a single install at the repo root wires everything up:
pnpm install
# run the full suite (component + unit tests)
pnpm test
# or a single project
pnpm test:vue3
pnpm test:unit