When I was a lad, my father sat me down and said David, life is going to get complicated. You’ll be faced with difficult choices, and it won’t always be clear which is the right path.

So far my life has been a breeze, except when it comes to implementing icons in a website.

Icon fonts are great. But network requests are like pet turtles. Half a dozen or so is totally normal and quite necessary, but each additional one brings you closer to madness. And async’s not an option because I don’t want a FOMI (flash of missing icons).

Embedding the font and accessing it via CSS classes is fine, but with that method, I’ll have font files, @font-face rules, css files and maybe a file of sass variables. Try two devs updating that in two branches and merging together again… Also I’m not using CSS*.

Icons as .svg files are a giant pain.

And if you’re using a png spritesheet then you don’t deserve React.

And so, for Malla**, I’ve implemented icons in a way that, I think, is the right way. Here are the ‘features’ of my approach:

Icons are just components

Icons are rendered inline as SVG (server-side too)

Code weight is tiny

Adding a new icon is adding one line of code — not 7 files

Totally independent of icon libraries if you want to make your own icons

So, how is this done?

First, a lesson in SVG

A shape, when represented in SVG, is defined by a bunch of coordinates. Here’s a trash icon:

M192 1024h640l64–704h-768zM640 128v-128h-256v128h-320v192l64–64h768l64 64v-192h-320zM576 128h-128v-64h128v64z

Imagine you want to have a React component called, say, <TrashIcon/> that renders, say, a trash icon. All you need to do is tell it to render a bit of SVG with those coordinates.

That’s a stateless function component.

Boom. Trash icon. Seven lines of code.

(Those coordinates happen to be in the context of a 1024x1024 grid, so we use the viewbox attribute to tell the SVG element that. Also that we want the end result to be 22px.)

We’re making excellent progress, we now have a component that we can use whenever we want to see a bin on the page.

As you probably guessed, the next step is to make it so we can show more than just a bin. Let’s turn that TrashIcon component into an Icon component and let it accept a prop called icon.

By the way, has anyone stopped to think how great it is that GitHub does syntax highlighting for JSX?

I pass in the icon name as a string, the component then ‘looks it up’ in my icons object using bracket notation, which returns the path.

Lovely, we have an icon component that will show either a trash icon

<Icon icon=“trash” />

or a Facebook icon

<Icon icon=“facebook” />

Lo, the parent component was pleased that the child component would take the burden of rendering itself and declared: “props to you”.

The next question is, where do I get all those coordinates from? Personally I just type them out in the shape I want, but perhaps you want someone else to do all the work for you.

IcoMoon is the best of all the icon packages out there*** and they have a nice interface for selecting and downloading icons. What we want is just a single .json file that has all the SVG definitions for our icons. There’s a button for that, God bless ‘em.