Re-useable (and re-colourable!) SVG icons

I’ve just started using the PINGCRM Laravel-vue Inertia project and they have a nice little Icon component with half a dozen SVG icons defined.

They use a basic v-if and then v-else-if checking the name, like this:

    <svg v-else-if="name === 'dashboard'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm-5.6-4.29a9.95 9.95 0 0 1 11.2 0 8 8 0 1 0-11.2 0zm6.12-7.64l3.02-3.02 1.41 1.41-3.02 3.02a2 2 0 1 1-1.41-1.41z" /></svg>
    <svg v-else-if="name === 'office'" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path fill-rule="evenodd" d="M7 0h86v100H57.108V88.418H42.892V100H7V0zm9 64h11v15H16V64zm57 0h11v15H73V64zm-19 0h11v15H54V64zm-19 0h11v15H35V64zM16 37h11v15H16V37zm57 0h11v15H73V37zm-19 0h11v15H54V37zm-19 0h11v15H35V37zM16 11h11v15H16V11zm57 0h11v15H73V11zm-19 0h11v15H54V11zm-19 0h11v15H35V11z" /></svg>
    <svg v-else-if="name === 'printer'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M4 16H0V6h20v10h-4v4H4v-4zm2-4v6h8v-6H6zM4 0h12v5H4V0zM2 8v2h2V8H2zm4 0v2h2V8H6z" /></svg>

And this works great for a small demo project but notice that the icons are pre-colored and you can’t recolour them using CSS classes in the parent node.

I googled “how to change SVG colours” and came across this post which explains a neat work-around for setting up re-useable SVG components.

Here is a summary; you setup your SVG icon library as display none: and then you use a <use> tag inline to display them.

<!-- define your icon "library" -->
<body>
    <svg style="display: none">
        <symbol viewBox="0 0 32 32" id="heart-icon">
        </symbol>
    </svg>
</body>

We assign an id to the icon symbol, and then re-use this heart icon anywhere in the page by referencing to its id with <use> , such as in a text button:

<button class="favorite-btn">
  <svg width="24px" height="24px">
    <use xlink:href="#heart-icon"></use>
  </svg>
    Favorite me!
</button>

 

Taking that one step further, if we first modify each SVG element to use a fill color of “currentColor” we can then over-ride the fill color using CSS.

So in our Icon.vue component we get rid of all those ugly v-else-if statements and replace them with symbols like this:

  <svg style="display: none">
    <symbol id="calendar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm320-196c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM192 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM64 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z"></path></symbol>
    <symbol id="photo" xmlns="http://www.w3.org/2000/svg"   viewBox="0 0 576 512"><path fill="currentColor" d="M480 416v16c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v208c0 44.112 35.888 80 80 80h336zm96-80V80c0-26.51-21.49-48-48-48H144c-26.51 0-48 21.49-48 48v256c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48zM256 128c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-96 144l55.515-55.515c4.686-4.686 12.284-4.686 16.971 0L272 256l135.515-135.515c4.686-4.686 12.284-4.686 16.971 0L512 208v112H160v-48z"></path></symbol>
  </svg>

** Notice the fill=”currentColor”

Then in our page, we include the Icon component and then use the icons with <use> tag (which I had never heard of before!)

      <Icon  />

      <Link class="btn-indigo" href="/properties/create">
        <svg width="24px" height="24px"  class="inline-block">
            <!-- colour the icons using CSS --> 
            <use class="text-orange-400" xlink:href="#photo"></use>
        </svg>
        <span class="px-2"> {{ __('Create') }}</span>
        <span class="hidden md:inline">&nbsp;{{ __('Property') }}</span>
      </Link>
      <Link class="btn-indigo ml-4" href="/properties">
        <svg width="24px" height="24px" class="inline-block">
            <!-- colour the icons using CSS -->
            <use class="text-yellow-300" xlink:href="#calendar"></use>
        </svg>
        <span class="md:inline h-5 px-2" >{{ __('Properties') }}</span>
      </Link>

And there we are – reuseable recolourable SVG icons!

Let’s Start a Project!

Contact Me