diessi.caBlog
August 02, 2016

SVG Images as React Components with Webpack

If you’ve ever tried to load inline SVG (using svg-inline-loader) into React, you know it seriously hurts people’s eyes.

import React from "react";
import IconRemove from "./icons/remove.svg";
const RemoveButton = () => (
  <button>
    <div dangerouslySetInnerHTML={{ __html: IconRemove }} />
    <span>Remove</span>
  </button>
);

So what if it looked like this instead?

import React from "react";
import IconRemove from "./icons/remove.svg";
const RemoveButton = () => (
  <button>
    <IconRemove />
    <span>Remove</span>
  </button>
);

Much better, don’t you think?

That’s what svg-react-loader does. It process your SVG file and returns a React component, which is compiled with Babel (more on this below).

Using the Loader

npm install svg-react-loader --save-dev

Refer to Webpack docs for more information on loaders usage. Also, make sure you have installed svg-react-loader’s dependencies.

1. In Module Request

The simplest method, although the configuration convention is preferred. Using svg-react-loader and babel-loader, import your icon just like:

import IconRemove from "babel!svg-react!./icons/remove.svg";

Add in your Webpack configuration file’s loaders array.

{
  test: /\.svg$/,
  loader: 'babel!svg-react'
}

Import your icon just like:

import IconRemove from "./icons/remove.svg";

Usage Examples

Loader in module request method (1):

import React from "react";
import IconRemove from "babel!svg-react!./icons/remove.svg";
const RemoveButton = () => (
  <button>
    <IconRemove />
    <span>Remove</span>
  </button>
);

Loader in Webpack config file method (2):

import React from "react";
import IconRemove from "./icons/remove.svg";
const RemoveButton = () => (
  <button>
    <IconRemove />
    <span>Remove</span>
  </button>
);

A Note on SVG Loaders

Sometimes, we don’t want all of our SVG files to be loaded as React components. If you use a SVG in a img element, for example, it may lead to conflicts. Fortunately, you can avoid them by being more specific in test regular expression:

{
  test: /\.inline.svg$/,
  loader: 'babel!svg-react'
},
{
  test: /\.jpe?g$|\.gif$|\.png$|^(?!.*\.inline\.svg$).*\.svg$/,
  loader: 'url'
}

Now, only SVG files ending with .inline.svg will be loaded as React components. You’re good to go!