Making SVG Icon Component in Vue
A Cool Way to Use SVGs Like Icon Fonts
After considering reasons to migrate vector icons from icon fonts to inline SVGs, I looked for a solution in Vue.js to replace icon fonts with SVGs, while still maintaining the flexibility and easy-of-use of using icon fonts — ability to change the size, color and other attributes easily through CSS.
One popular method is to use v-html
directive and html-loader
npm module to import SVGs into our Vue template and modify the rendered <svg>
element in Vue’s mounted()
lifecycle method. Styles can then be applied directly to the <svg>
or to its parent and everything can be wrapped in a component for reusability.
Creating Svg-icon Component
Let’s create Svg-icon.vue
component file with three props.
icon
string prop to pass the.svg
filename to importhasFill
boolean prop which tells the component iffill
property will be used to change the color of the<svg>
element, default is false i.e. nofill
growByHeight
boolean prop to determine to useheight
orwidth
to scale relative to thefont-size
, default is true i.e. useheight
We pass the icon .svg
file to html-loader
in require()
method which stringifies it and is rendered into <svg>
element by v-html
directive.
The mounted()
lifecycle method is where all modifications to the <svg>
element happen.
- Set either
height
orwidth
attribute of the<svg>
element to1em
(relative to 1x thefont-size
) determined bygrowByHeight
and usewidthToHeight
for the other. Since not all SVGs are square shaped, we calculatewidthToHeight
ratio from the rendered element so that the SVG scales proportionately to its original dimensions as the parent’sfont-size
property changes. - In order to set the
fill
attribute of the<svg>
element, we need override the inlinefill
that comes with the SVG file. WhenhasFill
is true, we recursively remove fill attributes from<svg>
element and its children. Then adding afill
value using CSS selector to its parent or the<svg>
element will do the trick. - Additional DOM attributes like
class
can also be added to the element which can be used to scoped-styling in the component
Creating Smile Icon
Let’s create a smile icon using icon fonts from Font Awesome as well as our Svg-icon
component.
Using Icon Fonts
<template>
<i class="fas fa-smile smile-icon"></i>
</template><style lang="scss" scoped>
.smile-icon {
font-size: 24px;
color: #aaa; &:hover {
color: #666;
}
}
</style>
The CSS selector for .smile-icon
class sets the font-size
and color
of the icon along with :hover
psuedo-class.
Using Svg-icon Component
<script>
import SvgIcon from './components/Svg-icon';export default {
name: 'my-component',
components: {
'svg-icon': SvgIcon,
},
}
</script><template>
<div class="smile-icon">
<svg-icon icon="smile-solid" :hasFill="true"></svg-icon>
</div>
</template><style lang="scss" scoped>
.smile-icon {
font-size: 24px;
fill: #aaa; &:hover {
fill: #666;
}
}
</style>
Above implementation is identical to the icon fonts method, except for the .smile-icon
class is in the parent element and color
attribute is replaced by fill
in the Svg-icon
component case. We also need to ensure that the smile-solid.svg
file is in the path that’s specified in our Svg-icon
component’s require()
method ( ./assets/svg/
).
Rendered HTML
This is the rendered HTML that v-html
outputs. Note: all fill
attributes are removed and height
and width
attributes are added to <svg>
.
<div class="smile-icon">
<svg height="1em" width="1em" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="smile" class="svg-inline--fa fa-smile fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512">
<path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm194.8 170.2C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.6-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.4-16.2 38.1 4.2 24.6 20.5z">
</path>
</svg>
</div>
Transitioning to SVGs
Since SVGs are considered the way of the future, it is good to migrate away from using icon fonts while still retaining the ease of use that icon fonts provide. The Svg-icon
component is an example of how we can use available libraries to abstract away the messy parts of <svg>
element, while mimicking the good part of using icon fonts!
Download SVGs from Zeplin
Additionally, I wrote a script to batch download SVGs from Zeplin. Check it out.