How to Create SVG Font Icon Web Component

Photo by Markus Winkler on Unsplash

Photo by Markus Winkler on Unsplash

If you ever worked with SVG icons in your web application you must understand how hard it is to work with icons. There is a constant need to resize and color them as well as animate them which is not easy when you have the files. For those and more reasons, SVG Font Icon in a Web Component solves almost everything.

Why SVG Font Icons?

There are obvious pros and cons when using SVG font icons versus using SVG inline so it may not suit you if you do very complex and specific things but SVG as fonts should cover most basic web application needs.

Props:

  • Easier to use: It is as simple as adding a class to an inline tag or setting a pseudo-element with a specific icon content.
  • Easier to control: With SVG Font you control SVG like you would control text with CSS color and font-size properties for example.
  • Performance: Font files are cached by the browser and normally the font icon files are smaller than the SVG files. This also means you only need to request a single file to load all icons.
  • Basic animations: Any text or inline element animation you can do applies to SVG fonts. You can animate the color, size, transform it, etc.
  • Browser support: If you still need to support IE and old Android browsers SVG fonts are your only options as SVGs are not supported in those.

Cons:

  • Sharpness: Fonts are anti-aliased which means that they may not appear as sharp as SVGs. However, that’s not normally something people complain about any font, so you should be fine.
  • Multi-color support: Like fonts, they can only be one color so if your icons have different parts of different colors, this is a problem. This can be fixed by composing icons into one and assigning colors to each but it's more work.
  • Complex animations: Obviously if you are intending to, for example, animate individual parts of the icons this is not possible for Font Icons. They can only be animated as a whole and basic stuff only.
  • Accessibility: SVGs are more accessible since they have accessible tags you can use inside to help screen-readers. This can be overcome with some special attributes. If you want to know more, I recommend this article on the topic.

So, make sure font icons are really a fit for your project. There are a lot of libraries offering robust solutions for this and for this article ill teach you how to create your own.

Optimize and clean SVG files

As a rule of thumb, I recommend you always optimize your SVG files regardless of how you planning on using them. By doing so, you increase their performance by clearing unnecessary things that don’t matter for rendering.

Optimizing will make sure the font icon files are the smallest they can be. In addition, it is required that your SVGs only use paths instead of other shapes so the font can be easily created. Failing to do so will generate fonts with missing parts or that do not look like their raw SVG version.

I use a package called [svgo](https://www.npmjs.com/package/svgo) which handles a bunch of SVG optimizations including turning shapes into paths.

npm install svgo

Given that all my SVG icons files exist inside a src/icons directory, I run the following command to optimize them.

svgo -f ./src/icons -o ./src/icons

It will simply optimize and override the files in place. You may choose to output to a different directory if you want. This is a nice command to run before you build your application.

Create Font files

To create font files from SVG I use a different package called [svgtofont](https://www.npmjs.com/package/svgtofont) which does an amazing job.

Given the following directory structure:

src/
-- icons/
-- fonts/
package.json

I run the following command to generate fonts named bfs :

svgtofont --sources ./src/icons --output ./src/fonts --fontName bfs

This will create a directory with all defaults including React, SASS, Less, Stylus, and CSS files. You can keep what makes sense to your project but for this example, I run this command with the following options to only create the font and the css files.

// .svgtofontrc
{
  "fontName": "bfs",
  "website": false,
  "outSVGReact": false,
  "css": {
    "output": "./src",
    "fileName": "bfs-icon",
    "include": "\\.(css)$",
    "cssPath": "./fonts/"
  }
}

Check the library README to learn more about the options and change them to fit your project structure and need.

Using the font

When you generate the fonts you get CSS files that you can import into your project at the top level. For my example, I get a bfs-icon.css which I can add to my page.

<link src="./src/bfs-icon.css" rel="stylesheet"></link>

To use that I simply need to attach the icon name to any inline tag like so:

<i class="bfs-search-icon"></i>

The name of the class will be the font name plus the SVG icon file name. So since I named my font bfs and I have a search-icon.svg file, I can use the class bfs-search-icon to display it.

Creating an Icon Web Component

To create an icon web component I’ll be using CWCO since it takes care of a lot of things for me, requires no build, it’s fast and light, and is super easy to use. I can simply add the following link to my HTML file to start:

<script src="https://unpkg.com/cwco/dist/cwco.min.js"></script>

First I’ll create a bfs-icon component like so:

const {WebComponent} = window;
class BFSIcon extends WebComponent {
}
BFSIcon.register();

Then I can specify which attributes I want to observe to cause the component to update and also give them default values to start:

const {WebComponent} = window;
class BFSIcon extends WebComponent {
   static observedAttributes = [
     'name',
     'size',
     'color'
   ];
   name = '';
   size = '16px';
   color = '#000';
}
BFSIcon.register();

From here I can tell it about the CSS font file I generated so it imports it for me by defining the stylesheet for the component.

const {WebComponent} = window;
class BFSIcon extends WebComponent {
   ...
   get stylesheet() {
      return `
	 <link href="./src/bfs-icon.css" rel="stylesheet"/>
      `;
   }
}
BFSIcon.register();

You can use link tag to specify the component external stylesheet. Because the web component content is placed inside the shadow root, this internal link will allow it to access the CSS content of that file. However, you still need the same link in the head tag of your document for it to import the files linked in the CSS file.

Then finally, we can define the content of our component with the template getter.

const {WebComponent} = window;
class BFSIcon extends WebComponent {
   ...
   get template() {
      return `
	 <i
          class="bfs-{name}-icon"
          attr.style.font-size="{size}, size"
          attr.style.color="{color}, color"
         ></i>
      `;
   }
}
BFSIcon.register();

Notice that I used curly braces to data bind the name attribute value inside the class to compose our icon class. I also used the [attr](https://cwco.io/documentation/attr-directive) directive to conditionally set the style attribute for color and font-size on the tag.

The final code looks something like so:

const {WebComponent} = window;
class BFSIcon extends WebComponent {
   static observedAttributes = [
     'name',
     'size',
     'color'
   ];
   name = '';
   size = '16px';
   color = '#000';
   get stylesheet() {
      return `
	 <link href="./src/bfs-icon.css" rel="stylesheet"/>
      `;
   }
   get template() {
      return `
	 <i
          class="bfs-{name}-icon"
          attr.style.font-size="{size}, size"
          attr.style.color="{color}, color"
         ></i>
      `;
   }
}
BFSIcon.register();

At last…

SVG font icons are the best way to work with icons in your project. I also recommend you always optimize your SVG files before using them, especially if they were handed to you by designers which normally use applications like illustrators to create icons.

To learn the full example of this project watch this full and more detailed walkthrough video:

Watch the embedded video

[ Source Code ]

Illustration for “How to Create SVG Font Icon Web Component”

YouTube Channel: Before Semicolon Website: beforesemicolon.com

Share this article