Flexible SVG components in React

Timothy Krechel
4 min readOct 20, 2018

--

TL;DR: Using SVGs inside of React components allows us to control their size and color and SVGR is the right tool to create and maintain many SVG components at once.

While getting started with a new project, a colleague asked me about a good way to include icons into a next.js based React application.

It’s been quite a while since I implemented an icon system in one of my previous projects, so I quickly opened the source files of that project to refresh my memories. In hindsight, I felt that my approach worked quite well for what we were doing and I decided to share my insights in this blog post. Let’s dive in!

Getting SVGs into our projects

Using SVGs on the web isn’t hard, the format is supported by all major browsers since IE9. Of course, there are multiple ways to include them into our projects, like using them in image tags, as background-images or directly inline.

While all approaches are easy, the latter offers the opportunity to create self-contained, on-the-fly-customizable icon components, so I wanted to make use of that.

Preview of the SVG file.

Suppose we have an icon SVG depicting an airplane, that we want to use in various colors and sizes throughout our project. The SVG code might look something cryptic like this:

<svg 
version=”1"
xmlns=”http://www.w3.org/2000/svg"
viewBox=”0 0 50 50"
>
<path
fill=”#FFF”
d=”M33.5 45.5c-.1 0-.2 0-.3-.1L25 41.3l-8.2 4.2c-.1 0-.2.1-.3.1-.1 0-.2 0-.3-.1-.2-.1-.3-.3-.3-.5v-5.3c0-.2.1-.3.2-.4l4.1–4.4v-4.2L5 35.1h-.2c-.1 0-.3 0-.4-.1-.2-.1-.3-.3-.3-.5v-5.2c0-.2.1-.4.3-.5L20 17.7V9.5c0–3.1 2.2–5.6 4.9–5.6s4.9 2.5 4.9 5.6v8.1l15.6 11.1c.2.1.3.3.3.5v5.2c0 .2-.1.4-.3.5-.1.1-.2.1-.4.1h-.2l-15.1–4.5v4.2l4.1 4.4c.1.1.2.3.2.4v5.3c0 .2-.1.4-.3.5 0 .2-.1.2-.2.2zM25 38c.1 0 .2 0 .3.1l5.9 3v-.6l-4.1–4.4c-.1-.1-.2-.3-.2-.4v-8.3c0-.2.1-.4.3-.5.1-.1.2-.1.4-.1h.2l15.1 4.5v-.9L27.2 19.3c-.2-.1-.3-.3-.3-.5V9.5c0–1.4-.9–2.6–1.9–2.6s-1.9 1.2–1.9 2.6v9.3c0 .2-.1.4-.3.5L7.2 30.4v.9l15.1–4.5h.2c.1 0 .3 0 .4.1.2.1.3.3.3.5v8.3c0 .2-.1.3-.2.4l-4.1 4.4v.6l5.9–3s.1-.1.2-.1z”
/>
</svg>

So far so good, your typical .svg file. What’s of notice is that there are properties for the viewbox and the path’s fill. While the viewbox specifies the area that contains the path, there are more possible properties on the root svg tag, specifically width and height as well as fill .

The fill property, for example, can be specified as

<svg ... fill="#f00">

and reused inside of the path tag (or tags) for the specific paths like so.

<svg ... fill="#f00">
<path
fill=”fill”
d=”M33.5 ...”
/>
</svg>
//the d property was shortened for readability purposes

Lord of the Props

This is a perfect opportunity for controlling these properties via props thrown into a React component that renders the svg tag. We can now easily define our Airport stateless functional component as

const Airport = props => (
<svg version={1} viewBox="0 0 50 50" {...props}>
<path
fill="fill"
d="M33.5 ..."
/>
</svg>
);
//the d property was shortened for readability purposes

and use it via:

<Airport width={20} height={20} fill='#fff' />

It’s over, it’s done! We got ourselves a nice, controllable little component, where we can specify height , width and fill to cover our various use cases. We are now true rulers of the SVG world, aren’t we? But what if we had to manage hundreds of icons in a large-scale application? Wouldn’t exporting, optimizing and setting up components take hours — and what if icons change? Oh, the mess!

SVGR to the rescue

There surely must be a package that handles all this — and SVGR is the one. After installing the dependency via npm install svgr in our project root, we can easily create React components off our many .svg files automatically.

Let’s add a new npm script to our package.json file and call it icons :

"icons": "svgr --replace-attr-value '#FFF=fill' -d ./src/icons/js ./src/icons/svg"

Basically, this command takes the path ./src/icons/svg as the location to our /svg directory containing all of our icons and outputs the icons as components into the ./src/icons/js directory. The --replace-attr-value is the magical part of the script, where we replace thefillattribute value of"#FFF” with "fill" as explained above.

A slick looking React component

After running this command via npm run icons , all our components are created inside of the /js directory. Suppose we had our airport.svg file inside of /svg , we now have the corresponding Airport.js file containing the code above — by merely lifting a finger. Awesome!

Taking this further

We might want to access the icons by a String value, or we might want to color multiple path inside our components differently, which is all possible. To keep this post concise, I will cover these aspects in the future. Stay tuned!

--

--