Day 6 - How to add inline svg icons to a vue project
life UserBit code design entrepreneurshipTLDR; 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>