Managing a custom collection of icons in a Vue app can be challenging at times. An icon font is easy to use, but for customization, you have to rely on third-party font generators, and merge conflicts can be painful to resolve since fonts are binary files.
Using SVG files instead can eliminate those pain points, but how can we ensure they’re just as easy to use while also making it easy to add or remove icons?
Here is what my ideal icon system looks like:
To add icons, you just drop them into a designated icons folder. If you no longer need an icon, you simply delete it.To use the rocket.svg icon in a template, the syntax is as simple as .The icons can be scaled and colored using the CSS font-size and color properties (just like an icon font).If multiple instances of the same icon appear on the page, the SVG code is not duplicated each time.No webpack config editing is required.
This is what we will build by writing two small, single-file components. There are a few specific requirements for this implementation, though I’m sure many of you wizards out there could rework this system for other frameworks and build tools:
webpack: If you used the Vue CLI to scaffold your app, then you’re already using webpack.svg-inline-loader: This allows us to load all of our SVG code and clean up portions we do not want. Go ahead and run npm install svg-inline-loader –save-dev from the terminal to get started.
The SVG sprite component
To meet our requirement of not repeating SVG code for each instance of an icon on the page, we need to build an SVG “sprite.” If you haven’t heard of an SVG sprite before, think of it as a hidden SVG that houses other SVGs. Anywhere we need to display an icon, we can copy it out of the sprite by referencing the id of the icon inside a
The icon component
Now let’s build the SvgIcon.vue component.
This component is much simpler. As previously mentioned, we leverage the
Error!
That’s it! If you want to use the icon component anywhere in your app without having to import it into every component that needs it, be sure to register the component in your main.js file:
// main.js
import Vue from vue
import SvgIcon from @/components/SvgIcon.vue
Vue.component(svg-icon, SvgIcon)
// …
Final thoughts
Here are a few ideas for improvements, which I intentionally left out to keep this solution approachable:
Scale icons that have non-square dimensions to maintain their proportionsInject the SVG sprite into the page without needing an additional component.Make it work with vite, which is a new, fast (and webpack-free) build tool from Vue creator Evan You.Leverage the Vue 3 Composition API.
If you want to quickly take these components for a spin, I’ve created a demo app based on the default vue-cli template. I hope this helps you develop an implementation that fits your app’s needs!
¹ If you’re wondering why we’re using SVG when we want it to behave like an icon font, then check out the classic post that pits the two against one another.