Feather icons usage in Vue.JS
Summarizing the comment thread and presenting another solution for posterity:
- The issue with the original code is that there's a missing call to
feather.replace
, which finds all the elements withdata-feather
attributes and replaces them with the appropriate icon's SVG. - Calling
feather.replace
in themounted
hook is good enough for simple use cases, but it doesn't allow for icons changing. (In general, it strikes me as a bad idea to let non-Vue code modify the HTML you're using Vue to render.) E.g.,<i v-bind:data-feather="iconName"></i>
isn't going to allow for subsequent updates. vue-feather-icon
appears to be a project that integrates better with Vue.
Below is a better way to use "vanilla" feather-icons
without running into the above issues. Here, we're dynamically updating the HTML content of a div
with the appropriate icon SVG by using a computed property that calls feather.toSvg
:
<template> <div id="app"> <h1>{{ message }}</h1> <div v-html="iconSvg"></div> <button @click="clicky">Click me</button> </div></template><script>import feather from 'feather-icons'export default { name: 'app', data: function () { return { message: 'Hello, World!', icon: 'flag' } }, computed: { iconSvg: function () { return feather.toSvg(this.icon) } }, methods: { clicky: function () { this.message = 'clicked' this.icon = 'circle' } }}</script>
This can also be done as a functional component, and you can use the icon-names to simply pick which svg to render.
You can also swap out feathers and use another svg-sprite
// Usage <div class="flex items-center p-2 mt-2 bg-white"> <x-svg icon="log-out" class="w-4 h-4" /> </div> // x-svg.vue <template functional> <svg fill="none" :viewBox="props.viewBox" :class="['stroke-' + props.stroke, data.class, data.staticClass]" class="inline-flex w-4 h-4 text-gray-500 stroke-current hover:text-gray-900 group-hover:text-gray-900" stroke-linecap="round" stroke-linejoin="round" :ref="data.ref" :style="[data.style, data.staticStyle]" v-bind="data.attrs" v-on="listeners" > <use :href="require('@/assets/img/feather-sptite.svg') + '#' + props.icon" /> </svg> </template> <script> export default { props: { icon: { type: String, default: 'alert-circle' }, stroke: { type: Number, default: 1, validator(v) { const sizes = [0.5, 1, 1.5, 2, 2.5] return sizes.includes(v) } }, viewBox: { type: String, default: '0 0 24 24' } } } </script>