How to Use Custom SVG Icons In Vue.js

SVG Icons in Vue.js

While there are many icon libraries that you can use in your Vue.js project, sometimes it becomes necessary to use custom SVG icons.

Rather than displaying the icons using the <img> tag, the best way to use SVG icons in a Vue.js project is to use them as Vue.js components. This gives you the flexibility of being able to change the icon color and manipulate other of its properties on the go.

To achieve this, you need to install an SVG loader in your project;

yarn add -D vue-svg-loader vue-template-compiler

// OR

npm i -D vue-svg-loader vue-template-compiler

Then you need to tell Webpack to use the just installed vue-svg-loader to load SVG files.

Add the following to your Webpack rules property;

module: {
  rules: [
    // ...
    {
      test: /\.svg$/i,
      oneOf: [
        {
          resourceQuery: /inline/,
          use: [
            {
              loader: 'vue-svg-loader',
              options: { svgo: false },
            },
          ],
        },
      ]
    },
  ]
}

Here we are using the resourceQuery property to tell Webpack when to use the vue-svg-loader to load SVG files. So unless we append ?inline to the filename when importing an SVG file, this loader will not be used. This is useful in cases where you need to treat some SVG images as regular files.

If you are using Nuxt.js

You just need to install the @nuxt/svg instead. This module already has the above configuration set.

yarn add -D @nuxt/svg

// OR

npm i -D @nuxtjs/svg

And add it to your nuxt.config.js file;

// nuxt.config.js

export default {
  buildModules: ["@nuxtjs/svg"],
};

Now to use a custom SVG icon in any of your components, you can import it as follows;

<template>
  <nav>
    <a href="https://github.com/vuejs/vue">
      <VueLogo class="logo" />
      Vue
    </a>
  </nav>
</template>

<script>
import VueLogo from './public/vue.svg?inline';

export default {
  components: {
    VueLogo,
  },
};
</script>

<style scoped>
.logo {
  width: 28px;
  height: 28px;
  margin-right: 10px;
}
</style>

Creating An Icon Component

If you are going to be using a lot of icons in your project, importing them individually is not ideal. So let's create a generic <Icon> component that we can easily use to import our icons.

// components/Icon.vue

<script>
export default {
  props: {
    name: {
      type: String,
      required: true,
    },
  },

  render(createElement) {
    try {
      const component = require(`~/assets/icons/${this.name}.svg?inline`)

      const data = {
        class: ['icon'],
      }
      const children = [createElement(component)]

      return createElement('span', data, children)
    } catch(e) {
      // console.log(this.name, e)

      return null
    }
  },
}
</script>

<style lang="scss">
.icon {
  display: inline-block;

  > svg {
    width: 1em;
    height: 1em;
    margin-top: -4px;
    fill: currentColor;
  }
}
</style>

The component uses the require function to load up SVG files from the assets/icons folder, it then wraps the imported SVG component in a span element which we use to apply some styles to the icons.

The component accepts a required name prop, which is the name of the SVG file we want to load, placed in the assets/icons folder.

Don't forget to register the component;

import Icon from 'components/Icon.vue'

Vue.component('Icon', Icon)

Now, all we need to do is add all our SVG icons to the assets/icons folder. And when you need to use anyone of them, you can easily use the Icon component to load them.

For example, if we have an SVG file with name vue.svg in our assets/icons folder, we can use it in our project as follows;

<Icon name="vue" />

And that's how to use SVG icons in Vue.js. If you have any questions feel free to drop them in a comment below. ✌🏽