Crayon Bits Blog

User Experience, Frontend, Code and Life

Day 6 - How to add inline svg icons to a vue project

life UserBit code design entrepreneurship

TLDR; jump to attempt 3

I ended up doing it without using any external plugins.

Why inline svg?

I wanted to create some icons for UserBit in sketch. In the past though I’ve had to update the icons color/size multiple times as I iterated over my products. So I decided to create SVG icons this time so I could tweak these properties in code itself. Upon some research I realized that for you to be able to control svg attributes through code, you need to have your SVG code inline in the template.

Attempt 1 - vue-svg-inline-loader

installed it

> npm i vue-svg-inline-loader --save-dev

after adding the respective configuration in vue.config.js, the render function started throwing a bunch of errors. I did not want to spend time dealing with this… so on to the next attempt

Attempt 2 - vue-svg-loader

So next attempt was to try vue-svg-loader and configuring it in vue.config.js:

chainWebpack: config => {
    const svgRule = config.module.rule('svg')

    // clear all existing loaders.
    // if you don't do this, the loader below will be appended to
    // existing loaders of the rule.
    svgRule.uses.clear()

    // add replacement loader(s)
    svgRule
      .use('vue-svg-loader')
        .loader('vue-svg-loader')
  }

basically this says, when webpack encounters .svg file, use the vue-svg-loader to load it as opposed to the regular vue-loader. While this config seems to have worked, this blanket application of rule meant all my current svg font icons failed to render - I’d have to use them the svg-loader way. This would turn out to be more work than it was worth.

Attempt 3 - create a component for each icon

Ok, so after dealing with these plugins, I took a step back and thought about what I really wanted to do. I simply want my icons to render inline and for me to control the color attribute of these icons (and perhaps the size). I took a look at the svg file itself.

<?xml version="1.0" encoding="UTF-8"?>
<svg width="44px" height="44px" viewBox="0 0 44 44" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g>
    <!- actual svg code ->
  </g>
</svg>

It occured to me that if I could just paste this code inline in my icon component, I’d be able to render it inline. I also noticed that the svg at several places referred to the color I was using. So if the svg was part of the template I could replace the hex with a prop (color):

before

<circle id="Oval-7" stroke="#8898AA" cx="7" cy="22" r="2"></circle>

after

<circle id="Oval-7" :stroke="color" cx="7" cy="22" r="2"></circle>

and in props

props: [
  'color'
]

So the single file component looks something like:

<template>
<span>
  <svg width="44px" height="44px" viewBox="0 0 44 44" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>My Icon</title>
    <desc>Created with Sketch.</desc>
    <defs></defs>
    <g id="icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Artboard" transform="translate(-90.000000, -64.000000)">
            <circle id="Oval-7" :stroke="color" cx="7" cy="22" r="2"></circle>
        </g>
    </g>
  </svg>
</span>
</template>

<script>
export default {
  name: 'ub-circle-icon',
  props: [
    'color',
  ],
};
</script>

<style lang="scss" scoped>
</style>

Usage

import the icon file

import CircleIcon from './icons/circle-icon.vue';

add it to components

components: {
  CircleIcon,
}

then use it on the template

<circle-icon
  color="#CB0881">
</circle-icon>