How to Load SVG with React and Webpack
Nov 20, 2019 • 7 Minute Read
Introduction
As developers, we want all our images to look sharp and nice, even when we scale them up. To achieve the level of sharpness we want for our websites using bitmap images, such as JPEGs, GIFs, and PNGs, we have to increase file size, which greatly impacts the performance of the website. Vector images, however, looks crisp regardless of screen resolution and are relatively small in size.
In this guide, we'll learn about Scalable Vector Graphics (SVG) and explore the standard way of importing SVG in a React Application bundled with Webpack.
What is SVG?
SVG is an XML-based markup language for describing two-dimensional-based vector graphics. SVG is essentially to graphics what HTML is to text.
SVG images basically take the place of traditional images in other formats like JPEG, PNG, TIFF or GIF.
Advantages of using SVG over other image formats are:
- SVG images can be searched, indexed, scripted, and compressed
- SVG images are scalable
- SVG can be created and edited with any text editor
- SVG images do NOT lose quality even if they are resized or zoomed
- SVG images can be animated, unlike other traditional image formats
Let's take a closer look at how to use SVG images. The xml code below creates a rectangle:
rectangle.svg
<svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="green" />
</svg>
The most basic way to embed an SVG via an <img> element is to reference it in the src attribute, as you'd expect. You will need a height or a width attribute (or both if your SVG has no inherent aspect ratio).
<img src="rectangle.svg" alt="A Rectangle Image with SVG" height="45px" width="45px" />
Usage with React
The easiest way of implementing an SVG in a React app is as follows:
const App = () => <img src="/images/rectangle.svg" alt="A Rectangle Image with SVG" />;
However, in most cases, SVGs are usually pretty small, and in these cases we are better off inlining the images as data URLs, limiting the amount of requests a browser has to make to the server in order to render the webpage.
To transform an SVG image into a Data URL, we will need an appropriate webpack loader in our bundler. The most common webpack loader for this is svg-url-loader, which can be added as shown below:
npm i svg-url-loader --save-dev
Add to webpack.config.js:
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 10000,
},
},
],
},
],
},
...
};
Import the file into your React app:
import rectangle from 'images/rectangle.svg';
const App = () => <img src={rectangle} alt="" />;
The output in the DOM will be something like this:
<img src="ebbc8779488b4073081931bd519478e8.svg" alt="" />
You can check out svg-url-loader for more on the configurations.
In the examples above, the svg-url-loader can only be used in the traditional way, including images in a web application such as background-image or content. The next question is how to use an SVG image as a React Component.
SVG as a React Component
The solution is not farfetched. We'll need the help of another awesome webpack loader called svgr, which, according to the website, transforms the SVG into a ready-to-use React component.
So how do we use this awesome tool? Lets start by updating our webpack.config.js:
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.svg$/,
use: ['@svgr/webpack'],
},
],
},
...
};
Then we can install it as a dev-dependency in the usual way:
npm install @svgr/webpack --save-dev
Once you start your application, Webpack will do its thing and you don't need to worry about your SVGs anymore. You can put your SVG files anywhere in your src/ folder and import them wherever you need them as React components.
Lastly, import the file in your React app:
import Image from 'path/image.svg';
const App = () => (
<div>
<Image />
</div>
)
This method is generally referred to as inline-svg.
A lightweight alternative solution to svgr is react-svg-loader.
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
loader: 'react-svg-loader',
options: {
jsx: true // true outputs JSX tags
}
}
],
},
...
};
And install as usual:
npm install react-svg-loader --save-dev
For the most part, we do not want all our SVG files to be loaded as a React components. We could combine the above methods depending on the use case. All we have to do is update our webpack configuration.
The example below uses svgr and url-loader, a webpack loader which transforms files into base64 URIs.
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
},
],
},
...
};
The usage in your application would look this:
import imageUrl { ReactComponent as Image } from 'path/image.svg';
const App = () => (
<div>
<img src={imageUrl} alt="" />
<Image />
</div>
)
Conclusion
This guide has provided you with a quick intro into how to import SVG into your React Application using webpack as the bundler.
Here are a few other resources on SVG and its numerous applications: