SVG sprite icons for React and Webpack

There are a lot of ways how you can use icons in your frontend, in this article I will explain everything you need to know about setting up a good SVG sprite icons solution in your React and Webpack app.

SVG Sprite Icons

The battle of icon solutions

Here is a quick list of different solutions for using icons in your app.

  • Sprite maps: you can use Gulp or Webpack to automatically generate a sprite map, this is a good solution but it is a lot of work, say for example you have a small icon in black, but you need to make it red? Lot’s of work… also keep in mind you need to keep multiple sprite maps for your shiny retina devices. More information about sprite maps.
  • Icon font: Icon fonts are awesome, but it can be a pain in the ass when a certain browser (ahumm… IE) renders the icon a few pixels to the top. More information about icon fonts and it’s pros and cons.
  • SVG sprite icons: This is the way to go, its verbose, easy, lightweight and very maintainable.

Now I don’t want to go into much detail about all the pros and cons, but here is a list for more convincing:

Repository

For those who want to go straight to the solution:

https://github.com/mikevercoelen/svg-icons-react-webpack

Setting up Webpack loaders

First lets install the loaders:

installation

npm install svg-sprite-loader svgo svgo-loader --save-dev

As you can see we also install svgo and svgo-loader, this is to optimize the svg’s and I highly recommend you do this too. Now lets update our Webpack configuration, depending on your project structure, you have to find the best place where to add these rules.

Note: I am using Webpack 2, I highly recommend you also use Webpack 2. If you are not familiar with the Webpack 2 configuration rules check this article out: Migrating to Webpack 2.

webpack.config.js

// ...

module.exports = {

  // ...

  module: {

    // ...

    rules: [{
      test: /\.svg$/,
      include: path.join(srcPath, 'icons'),
      loaders: [
        'svg-sprite-loader?' + JSON.stringify({
          name: '[name].[hash]',
          prefixize: true
        }),
        'svgo-loader?' + JSON.stringify({
          plugins: [
            { removeTitle: true },
            { convertPathData: false },
            { removeUselessStrokeAndFill: true }
          ]
        })
      ]
    }]
  }
};

Creating the Icon React component

Now we have to create an Icon component. I don’t use any css, and use styled-components to keep things simple here, I also recommend you check out the library.

components/icon/icon.js

import React from 'react';
import styled from 'styled-components';

const Icon = styled.svg`
  color: inherit;
  fill: currentColor;
  width: inherit;
  height: inherit;
`;

export default ({ glyph }) => (
  <Icon>
    <use xlinkHref={glyph} />
  </Icon>
);

As you can see we add color, width and height inherit rules. This way, when we want to display an icon in our application, we use a wrapper around the icon and give that the required styling, instead.

A lot of examples of implementing React SVG icons add width and height properties to the Icon component, but I wouldn’t recommend this, styling should define it’s dimensions and looks, not properties.

We need the fillColor property so our SVG icon can inherit it’s color.

Adding icons

Now its time you create an icons folder in your project source directory. Put in some svg’s which we can use for now.

Where to get icons?

A nice place to get icons is The Noun Project I highly recommend this website. You can download them for free if you give credits. Get creative with this.

Using icons

Now lets look at an example View below and you can see how easy it is to use the icons.

components/exampleview.js

import React from 'react';
import styled from 'styled-components';

const IconHuge = styled.div`
  display: inline-block;
  margin: 8px;
  color: #e74c3c;
  width: 64px;
  height: 64px;
`;

const IconSmall = styled.div`
  display: inline-block;
  margin: 8px;
  color: #1abc9c;
  width: 16px;
  height: 16px;
`;

import Icon from '../Icon/Icon';

import Cross from '../../icons/Cross.svg';
import Location from '../../icons/Location.svg';

export default () => (
  <div>
    <div>
      <IconHuge>
        <Icon glyph={Cross} />
      </IconHuge>
      <IconHuge>
        <Icon glyph={Location} />
      </IconHuge>
    </div>
    <div>
      <IconSmall>
        <Icon glyph={Cross} />
      </IconSmall>
      <IconSmall>
        <Icon glyph={Location} />
      </IconSmall>
    </div>
  </div>
);

Final thoughts about the SVG sprite icons solution

Feel free to check out the repository for the full implementation of SVG sprite icons with React and Webpack. As you can see in the HTML, a SVG sprite map is generated for you.

Thanks for reading,

Cheers