Simplified Dynamic SVG Icon Component

February 8, 2019

Simplified Dynamic SVG Icon Component

Well this is embarrassing. One of my flaws is that sometimes I tend to jump to a conclusion before I have all the facts. I guess a strength is recognizing this flaw. Do they cancel each other out? Maybe. No one likes egg on their face but I'll admit that my previous article was flawed. I will leave it intact for posterity though, both to show the errata and to provide an alternative way of doing things.

Massive mea culpa: I didn't read the TailwindCSS documentation carefully, or I just didn't pay enough attention, but the framework does contain support for SVG fill and stroke. Basically you can apply .fill-current and/or .stroke-current to an svg element and presto, your icon is colored based on the .text-<color> class that is also applied to it.

What's even funnier is that Adam specifically mentions in the documentation the two SVG icon libraries I love the most: Zondicons and Feathericons. Since one is fill-based, while the other is stroke-based, this new and improved dynamic component wrapper should work equally well for both libraries.

As a result, the API for my dynamic icon component can be simplified a lot.

This

<v-icon icon="menu" fill="red"></v-icon>

becomes

<v-icon icon="menu" class="text-red fill-current stroke-current"></v-icon>

But I can simplify it even more by always applying fill-current and stroke-current inside the scoped CSS of the VIcon.vue component:

<style>
svg {
    @apply cursor-pointer;
    @apply inline-block;
    @apply stroke-current;
    @apply fill-current;
}
</style>

I no longer need the fill prop, nor the dynamicFill computed props.

Another thing that is no longer required is the size prop. It turns out that you can simply apply Tailwind w- and h- classes to the svg element. However, I decided to keep the size prop in order to offer finer control over icon sizing, in pixels. However, to keep the UI consistent, I would strive to use Tailwind's classes instead.

In summary, to generate a blue 12px menu icon I would do this:

<v-icon icon="menu" class="text-blue h-3 w-3"></v-icon>

Note The above computes to 12px in my case because I have the font size on the root body element set to 16px. Hence, h-3 and w-3 are defined as 0.75rem in Tailwind's default config, which evaluates to 0.75 * 16px = 12px.

There you go, while the previous version works just as well, this updated one - I think - is simpler and overall better.

VueJS SVG TailwindCSS
Liked this article? Share it on your favorite platform.
Picture of me