Search code examples
svgiconsreactjsloaderwebpack

How do I load SVGs directly in my React component using webpack?


I would like to render a material design icon directly in my NextButton component using webpack. Here's the relevant part of my code:

var NextIcon = require('material-design-icons/navigation/svg/production/ic_chevron_right_18px.svg');

var NextButton = React.createClass({
  render: function() {
    return (
      <Link to={this.props.target} className='button--next'>
        {this.props.label} {NextIcon}
      </Link>
    )
  }
});

But this isn't working as I thought it would. It seems to output the svg as a string, rather than an element.

I've tried using raw-loader, img-loader, url-loader, file-loader and svg-loader but I can't find the correct way to do this.


Solution

  • Since your SVG content is stored as a string and not as a React element, you'll need to use Dangerously Set innerHTML.

    var NextIcon = require('material-design-icons/navigation/svg/production/ic_chevron_right_18px.svg');
    
    var NextButton = React.createClass({
      render: function() {
        return (
          <Link to={this.props.target} className='button--next'>
            {this.props.label} <span dangerouslySetInnerHTML={{ __html: NextIcon }} />
          </Link>
        )
      }
    });
    

    You could perhaps work your way around this by creating a webpack loader that automatically does this for you whenever you require a SVG file.

    dangerouslySetInnerHTML.loader.js

    module.exports = function(content) {
        return (
            'module.exports = require("react").createElement("span", {' +
                'dangerouslySetInnerHTML: {' +
                    '__html: ' + JSON.stringify(content) +
                '}' +
            '});'
        );
    };
    

    webpack.config.js

    loaders: [
      {
        test: /\.svg$/,
        loader: require.resolve('./dangerouslySetInnerHTML.loader'),
        exclude: /node_modules/,
      },
    ],
    

    The previous code snippet would then become:

    var NextIcon = require('material-design-icons/navigation/svg/production/ic_chevron_right_18px.svg');
    
    var NextButton = React.createClass({
      render: function() {
        return (
          <Link to={this.props.target} className='button--next'>
            {this.props.label} {NextIcon}
          </Link>
        )
      }
    });