Add SVG icons

As plain markup

The simplest way to use SVG icons in Gridsome is to just add them as normal markup. This gives a lot of flexibility with the power of Vue. Here is an example where we have added an icon from https://feathericons.com/ as markup.

<template>
 <svg
  xmlns="http://www.w3.org/2000/svg"
  width="24" height="24"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
  class="feather feather-bell">
    <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
    <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
  </svg>
</template>

Using SVGs as Components

You can import SVGs as you do with any other Vue component with vue-svg-loader. Start by installing the library:

# NPM
npm i -D vue-svg-loader

# Yarn
yarn add -D vue-svg-loader

You will need to update the webpack config in gridsome.config.js to use the new loader:

module.exports = {
  chainWebpack: config => {
    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .use('vue-svg-loader')
      .loader('vue-svg-loader')
  }
}

Then you can import your SVGs from within your Vue templates like any Vue component:

<script>
  import Brand from '~/assets/svgs/Brand.svg'
  export default {
    components: {
      Brand
    }
  }
</script>

FontAwesome SVG Icons

FontAwesome is one of the most popular icon libraries out there, and with version 5, they've made it incredibly easy to use with Vue without bloating your codebase with a lot of icons/styles you're not using. We can start implementing it in our Gridsome site by installing a few needed items:

# NPM
npm i -D @fortawesome/{vue-fontawesome,fontawesome-svg-core,free-brands-svg-icons}

# Yarn
yarn add -D @fortawesome/{vue-fontawesome,fontawesome-svg-core,free-brands-svg-icons}

The @organization/{package,package} is a shorthand format for installing multiple packages within an organization. The above is equivalent to:

npm i -D @fortawesome/vue-fontawesome @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons

When the packages have finished installing, you'll want to open (or create) the src/main.js file in your project and add the following:

import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { config, library } from '@fortawesome/fontawesome-svg-core'
import { faGithub, faTwitter } from '@fortawesome/free-brands-svg-icons'
import '@fortawesome/fontawesome-svg-core/styles.css'

config.autoAddCss = false;
library.add(faGithub, faTwitter)

export default function (Vue) {
  Vue.component('font-awesome', FontAwesomeIcon)
}

You can now use the icons anywhere in your components/templates:

<font-awesome :icon="['fab', 'github']"/>
<font-awesome :icon="['fab', 'twitter']"/>

And best of all, the SVG for GitHub/Twitter icons will be the only ones added to our final build. Make sure you read the docs on vue-fontawesome to get full details on how to use the whole suite of FontAwesome fonts together.

Purge CSS

If you are using Purge CSS you have to include Font Awesome classes in the whitelist for the icons to work properly in the production environment. A code example with Tailwind and Purge CSS for gridsome.config.js:

class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-Za-z0-9-_:\/]+/g) || []
  }
}

module.exports = {
 ...,
 chainWebpack: config => {
    config.module
      .rule('css')
      .oneOf('normal')
      .use('postcss-loader')
      .tap(options => {
        options.plugins.unshift(...[
          require('postcss-import'),
          require('postcss-nested'),
          require('tailwindcss'),
        ])

        if (process.env.NODE_ENV === 'production') {
          options.plugins.push(...[
            require('@fullhuman/postcss-purgecss')({
              content: [
                'src/assets/**/*.css',
                'src/**/*.vue',
                'src/**/*.js'
              ],
              extractors: [
                {
                  extractor: TailwindExtractor,
                  extensions: ['css', 'vue', 'js']
                }
              ],
              whitelist: ['svg-inline--fa'],
              whitelistPatterns: [/shiki/, /fa-$/]
            })
          ])
        }
        return options
      })
  }
}

Using vue-svg-inline-loader

Webpack loader used for inline replacement of SVG images with actual content of SVG files in Vue projects. More info on the loader can be found here.

First install loader using:

# NPM
npm i -D vue-svg-inline-loader

# Yarn
yarn add -D vue-svg-inline-loader

Then you need to modify gridsome.config.js:

module.exports = {
  chainWebpack: config => {
    config.module
    .rule("vue")
    .use("vue-svg-inline-loader")
    .loader("vue-svg-inline-loader")
    .options({ /* ... */ });
  }
};

After that you can use your svgs like this:

Basic inline SVG sprite usage with svg-sprite keyword directive:

<img svg-inline src="~/assets/svg/example.svg" alt="example" />

Which replaces into:

<svg svg-inline svg-sprite focusable="false" role="presentation" tabindex="-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <use xlink:href="#svg-sprite-md5hash" href="#svg-sprite-md5hash"></use>
</svg>
<!-- ... -->
<!-- will get injected right before root closing tag in Vue component -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">
  <symbol id="svg-sprite-md5hash" xmlns="http://www.w3.org/2000/svg" viewBox="...">
    <path d="..."></path>
  </symbol>
  <!-- ... -->
</svg>

Edit this page on GitHub