The guide to integrating and styling icon systems — inline SVG and icon components

Claudia Romano
Nucleo
Published in
11 min readJun 28, 2018

--

There are different options when it comes to integrating icons in a design system. Each option has its pros and cons. Although there’s no such thing as “the perfect method”, we’ll help you find the one that suits your needs. In this two-article series, we’ll go over the main integration techniques, and we’ll see some practical code examples.

This guide is the answer to all the requests we receive at Nucleo about how to use the icons exported via the app. The Nucleo icon manager offers plenty of export options to choose from, but it’s not always straightforward which one does what. Until today 😋!

Quick note: you don’t need to be a developer to create an icon system. It’s quite easy for a designer to follow along with the techniques explained in this guide, and be part of the process that goes beyond delivering bare assets to the developer friends.

The icon integration methods that we will cover are:

Part 1
- Inline SVG
- Icon Components

Part 2
- SVG Image Sprites
- SVG Symbols
- Icon Fonts

Inline SVG

This is probably the easiest way to include icons in your project: copy the code of the icon and paste it in your document where you want the icon to be visible.

<button>
<svg viewBox="0 0 64 64" width="64" height="64">
<!-- svg content here -->
</svg>
</button>

In addition to the ease of use, this technique allows you to customize your icons using CSS. For example, to change the color of your icon to red, you can define (or overwrite) the fill presentation attribute:

svg {
fill: red;
}

It is crucial you understand the specificity of presentation attributes. Let’s consider the following code:

<svg viewBox="0 0 16 16" width="16" height="16>
<title>switcher</title>
<path d="..." fill="blue"></path>
</svg>

If you add to your CSS:

svg {
fill: red;
}

your icon will still be blue. To update its color, you should target the path element:

svg path {
fill: red;
}

or, if there are more elements:

svg * {
fill: red;
}

Presentation attributes make it easy for us to customize an icon using CSS but still, it is always a good idea to optimize the code of the icon so that you can target only the SVG element and still be able to customize the entire icon.

Let’s consider this example:

<svg width="64" height="64" viewBox="0 0 64 64">
<path d=".." fill="blue"></path>
<path d=".." fill="blue"></path>
</svg>

The SVG is composed of two path elements, both having a fill attribute defined (fill=”blue”).

Before including the code in our page, we could remove the fill attribute from the paths and add it to the SVG element instead:

<svg width="64" height="64" viewBox="0 0 64 64" fill="blue">
<path d=".."></path>
<path d=".."></path>
</svg>

Now we can change the color of the icon targeting only the SVG element:

svg {
fill: red;
}

Note: if you remove the fill attribute from the path elements and you do not add it to the SVG element, the icon will turn black. That’s because the default value of the fill attribute is black.

But fill is not the only attribute that can be used to color an icon: we have the stroke attribute as well. While the fill is used to set the color inside an element, the stroke is used to color the border of the element.

Let’s consider the following example:

<svg width="64" height="64" viewBox="0 0 64 64">
<path d=".." fill="none" stroke-width="2" stroke="blue"></path>
<path d=".." fill="none" stroke-width="2" stroke="blue"></path>
</svg>

We can do the same as we did for the fill attribute: remove the stroke value from the path elements and add it to the SVG element. Once again, in our CSS we can define the SVG presentation attribute:

svg {
stroke: red;
}

Great! Everything seems to be working fine. But what happens if we have an icon with mixed elements, some of them have a fill value and others a stroke one? This is quite a common case, and you’d still like to be able to customize them using the same snippet of code:

svg {
stroke: red;
fill: red;
}

For example, let’s consider this icon:

<svg width="32" height="32" viewBox="0 0 32 32">
<circle cx="16" cy="16" r="15" fill="none" stroke-width="2" stroke="blue"></circle>
<path d="..." fill="none" stroke-miterlimit="10" stroke-width="2" stroke="blue"></path>
<path d="..." fill="red"></path>
</svg>

I have been using the color red for the fill and the blue for the stroke.

Now if we move these attributes form the single elements to the SVG we have:

<svg width="32" height="32" viewBox="0 0 32 32" fill="red" stroke="blue">
<circle cx="16" cy="16" r="15" fill="none" stroke-width="2"></circle>
<path d="..." fill="none" stroke-width="2"></path>
<path d="..."></path>
</svg>

But now you can see the eyeglasses have a stroke that was not there before. Why is that?

You need to keep in mind these two simple rules:

  • if you want that an element does not inherit the stroke value from the SVG element, you need to add a stroke=”none” to that element;
  • if you want that an element does not inherit the fill value from the SVG element, you need to add a fill=”none” to that element.

Since the default value of the fill attribute is black, all the tools you use to draw SVG icons will automatically add a fill=”none” to the elements that have no fill. You do not have to worry about manually including it.

It is not the same for elements that do not have a stroke value: the default value of stroke is none so the graphic tools may not include stroke=”none” in the SVG code exported. In this case, you need to manually add stroke=”none” to the elements that do not have a stroke so they do not inherit it from the SVG element .

Unfortunately, the process of optimizing the SVG code is not always straightforward. So far, we have only considered simple icons (2 or max 3 elements per icon), but in real life, you can have more complicated SVG composed of multiple groups that may contain subgroups. Different stroke and fill values could be applied to groups, as well as their children.

This is the reason why I have been using a slightly different optimization method which has been working pretty well so far, regardless of the complexity of the icons.

These are the steps I follow:

  1. if the fill attribute is defined (and is different from “none”), I remove it from the element;
  2. if the stroke attribute is defined (and is different from “none”), I replace it with stroke=”currentColor”, so that I can set its value in CSS using the color property;
  3. I add the fill attribute only to the SVG element.

Using this tecnique, our SVG becomes:

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<circle ... fill="none" stroke-width="2" stroke="currentColor"></circle>
<path ... fill="none" stroke-width="2" stroke="currentColor"></path>
<path ...></path>
</svg>

And our CSS code will be:

svg {
color: blue; //this will target the stroke
fill: red; //this will target the fill
}

If you want to use the same color for both stroke and fill, then:

svg {
color: blue;
fill: currentColor;
}

If you’re setting an icon system, most likely you’re going to need icon variations. By using inline code, it is really easy to create color themes for your icons. For example, you can have a class for icons on a dark background and a class for icons on a light background:

svg.theme-dark {
color: #fff;
}
svg.theme-light {
color: #000;
}

And you could do the same to create hover effects or active states for your icons.

So far, we have been focusing on the icon color, but there are other attributes that can be customized.

For example, for icons that have a stroke attribute, you can customize the width of the stroke (using the stroke-width attribute).

In this case, these are the additional steps to follow:

  1. if the stroke-width attribute is defined, I remove it from the element;
  2. I add the stroke-width attribute to the svg element.

Now you can easily create variations for your stroke-width as we did for the colors:

svg.stroke-4 {
stroke-width: 4;
}

Pros of using a system based on inline svgs

As we have seen so far, using inline icons is super easy and does not require any set-up for it to work. It is really just about coping and pasting your icons.

If you are working on a quick prototype, for example, and you don’t really need to worry about updating/maintaining your icons, then this is the method I would go for.

If you are working on a more complex project, a better solution would be using icon components (more on this later in the ‘Icon Components’ section).

The process of using inline icons shines if used in combo with a tool like Nucleo that takes care of formatting the icon code for your, as well as giving you a visual presentation of the icons.

In Nucleo, right-click on the icon you need to export (or click the gear icon) and select ‘Copy SVG code’.

This will copy the icon code to your clipboard. Easy peasy!

By default, the ‘Copy SVG code’ does not remove the presentation attributes from the svg; if you want to remove them (i.e., you need to customise your icons), go to the app Settings page (accessible by clicking Account > Settings or pressing ⌘+, on Mac or Ctrl+, on Windows) and check the ‘Remove inline colors from SVG code’ and/or the ‘Remove stroke-width values’ option (under the ‘Copy Icon via context menu’ section). You’re done!

Icon components

If you are using inline icons as described in the previous section, then you may face issues if you need to update the code of one of them.

Let’s say you have been using a home icon all around your website; if you decide you want to use a different home icon, then you need to go through all the pages where the icon has been used and manually update its code. This could be quite time-consuming and prone to error.

This is where the icon components come in handy!

A component is basically a block of code: once you have defined it, you can use it multiple times on your site.

If you need to update the content of that component, you only need to update that block definition, without worrying about where that component had been used.

You can apply this concept to the icons and create a component for each of your SVGs.

You are still using them as inline code (so everything we said about exporting and customizing icons still applies) but this time in a way that makes maintaining your icon system way faster.

The way you define an icon component depends on the tools you are using to build your site.

For example, if you are creating a static website, chances are you are using an HTML templating language that allows you to import components in your site pages.

In this case, you can create an ‘icons’ folder where you can save all your SVG files and then import them in your pages using something like:

<button>
{% include "icons/demo-icon.svg" %}
</button>

Note: the ‘include’ syntax I have been using is the one of Nunjucks. If you use another templating language, the syntax could be slightly different, but the technique remains the same.

Once included in your pages, you can keep styling your icons as explained in the ‘Inline SVG’ section.

The same happens if you are using a server-side language like PHP. Once you have created your ‘icons’ folder, you can import them in your pages using:

<button>
<?php include("icons/demo-icon.svg"); ?>
</button>

If you are using JavaScript frameworks (like React.js or Vue.js), then the logic to create your icon components is the same but you may need to add some additional steps (depending on the framework you are using).

If you are using React, for example, chances are you are going to need a .jsx file for each one of your icons.

The JSX syntax is slightly different from the HTML one; for example, it uses camelCase naming convention (that means an attribute like ‘stroke-width’ has to be converted to ‘strokeWidth’) and some other variations (like ‘class’ becomes ‘className’).

So, for example, this icon:

<svg viewBox="0 0 32 32" width="32" height="32" class="bakery">
<title>bakery</title>
<path d=".." fill="none" stroke-width="2" stroke="currentColor"/>
<path d=".." fill="none" stroke-width="2" stroke="currentColor"/>
</svg>

becomes:

<svg viewBox="0 0 32 32" width="32" height="32" className="bakery">
<title>bakery</title>
<path d=".." fill="none" stroke="currentColor" strokeWidth="2"/>
<path d=".." fill="none" stroke="currentColor" strokeWidth="2"/>
</svg>

If you are interested in reading more about using inline SVG icons with React.js/Vue.js, here are two articles I would suggest:

If you’re working on a React.js or Vue.js project, you can use Nucleo to export the icons of your project with the right formatting:

Here’s the list of props used:

  • width: icon width;
  • height: icon height;
  • fill: icon color (available if ‘Replace inline colors with props’ was checked while exporting);
  • strokewidth: icon stroke width (available if ‘Replace stroke-width values with props’ was checked while exporting).

If you are using the Nucleo icon library, then you have an additional prop — secondaryfill — that you can use to pass a secondary color (to create bi-color icons).

Alternatively, you can copy the JSX or VUE code using the icon context-menu.

In the app Settings page you’ll find some additional options (‘Remove inline colors from SVG code’ and/or ‘Remove stroke-width values’) to replace fill/stroke and/or stroke-width with props.

App tip: in the icon context-menu, you’ll find three different options to copy the icon code → SVG, JSX, VUE. In most cases, you’ll need just one of them. To remove the options you don’t need, go to the app Settings page and uncheck the ones you do not need.

Bonus tip: align inline icons to text

As a last tip, let’s take a look at the CSS code we use to align inline SVG icons to the text.

Let’s say we have:

<p class="icon-text-aligner">
<svg class="icon" viewBox="0 0 48 48" aria-hidden="true">
<!-- icon content here -->
</svg>
Text here
</p>

In CSS you can use the following snippet:

.icon-text-aligner {
/* element that contains icon + text */
display: flex;
align-items: center;
}
.icon-text-aligner .icon {
/* svg element */
display: inline-block;
height: 1em;
width: 1em;
color: inherit;
margin-right: 0.4em; //you can change this
flex-shrink: 0;
}

And you are done!

We hope this article was helpful! In the next article we’ll take a look at SVG image sprites, SVG symbols and icon fonts.

Feedback/suggestions are more than welcome 🙂

--

--