Just one way. Not the only way.
Sometimes, especially for a project within a company, you’ll need an icon library, and you can’t use something like font-awsome or feather-icons. This icon-library needs to be easy to extend, easy to use and easy to maintain.
Good to know before jumping in
Our solution might end up looking something like this
This is pretty straightforward. Again, it’s only a suggestion. There’s no right or wrong approach here.
Part 1 - How do we keep store our SVGs?
An icon is just an SVG, in our case at least. We need a way to keep all our SVGs in one place. Also, this place should be easy to access/change/augment. We can do things with a simple object. Something like this:
For brevity, I didn’t include the actual SVG code, since that would just make the example more difficult to follow.
Ok, so we have an export here that has an object with a bunch of properties, one for each icon. If we want to access the SVG for an icon, we can do something like this:
const playSvg = icons[‘play’]; (where we import the file like this
import icons from ./icons-svgs.ts
This has a few problems though. One of them is not being type safe 🙅♂️. Meaning, you don’t know if there’s a typo in there, you don’t know the name of the icon you want to access, you have no autocomplete. You’ll find all this out at runtime. Not great.
Part 2 - Here comes the Icon Service
To make our lives easier, let’s create a reusable service that will simplify the way we can access our icons. It can look something like this.
Here we are doing 2 things:
- We create a type:
IconTypeso we always know which icons are available. This makes the icons typesafe.
- We have a method that returns the SVG string to be used in the HTML template.
That’s it. Not a lot of code, but our life is so much better now.
Now, who will use this service? Do we, as consumers of the
IconComponent care about it?
Part 3 - Introducing the standalone component
No, we do not.
The actual API of our Icon Library revolves around 1 component. So, the service above is just an implementation detail. Here’s how the consumer of that service might look like:
A couple of things are happening here.
First, the component is
standalone . That’s the new-ish Angular feature. Very useful in this case, since it allows us to have a VERY atomical component. Very nice!
ChangeDetection should definitely be
OnPush. No reason for any other way.
Then, we’re declaring our inputs. These are a reflection of the desired API we defined in the beginning this post.
nameis used to access the correct SVG. Notice how nice is to have this typed.
sizeis used to allow the consumer to control the space taken by our icon.
After the inputs, we need to use the
DomSanitizer to bypass the security while passing along the HTML code for the SVG. This is because otherwise Angular will escape all the "weird" characters to prevent any sort of injection. Security as a priority.
svg property is being used in the template by biding it to the
innerHTML of the
Part 4 - How to extend?
If you want to extend this with a new icon, it couldn’t be simpler. Go the the
icons.ts file, add a new property and assign to it the SVG of the new icon. That’s it. From this point on, the new icon is available to you with the name you gave it.
Part 5 - How to replace?
Did you manage to get approval to use feather-icons? Or do you not need custom icons anymore and want to instead use an already available solution? Simple. You have only one entry point here. Your
IconComponent can switch implementations, and the consumers need not care about it. Profit!
Part 6 - Congrats!
You made! You read through another post about something mildly interesting. Good job! Hope at least 10% of this was useful to you. 🎉
If you want to know more about this, or something doesn't make any sense, please let me know.
Also, if you have questions, you know where to find me… On the internet!
Be kind to each other! 🧡
Over and out
One way of building an SVG icon library for your project https://catalincodes.com/posts/one-way-of-building-an-svg-library #Angular