Making React SVG integration easy
What this is all about
I've been working with React for the past four years, and usually, there was a lot of boilerplate code related to SVG icons. Each time to add an icon, I'd have to do a few repeatable steps again and again. We wanted to simplify this process, and finally, the most convenient one was invented, which I would like to share with you.
What is the goal
We wanted to make the process of SVG integration easy without losing any of its features:
- Plug and Play SVG integration.
- Ability to change color.
- Responsiveness.
- No boilerplate code.
Several approaches to use SVG
Let's take a look at the approaches for integrating SVG in React:
1. SVG as Image
We can use SVG as a source to image tag:
const App = () => {
return (
<img src="/images/icons/search.svg" />
)
}
This solution keeps things simple, which is okay. However, the main disadvantage is that we can't change the color "on the fly" because SVG markup is not exposed to the DOM tree.
2. SVG as plain JSX
We can insert SVG code to React "render" method:
const App = () => {
return (
<svg xmlns="<http://www.w3.org/2000/svg>" width="512" height="512" viewBox="0 0 512 512">
<path d="M508.87,478.71,360.14,330a201.64,201.64,0,0,0,45.19-127.31C405.33,90.92,314.42,0,202.67,0S0,90.92,0,202.67,90.92,405.33,202.67,405.33A201.64,201.64,0,0,0,330,360.14L478.71,508.88a10.67,10.67,0,0,0,15.08,0l15.09-15.09A10.66,10.66,0,0,0,508.87,478.71Zm-306.2-116c-88.23,0-160-71.77-160-160s71.77-160,160-160,160,71.77,160,160S290.9,362.67,202.67,362.67Z"
/>
</svg>
)
}
Using this approach, we can do whatever we want with SVG. However, in exchange we have some cons to think about:
- We would need to rewrite all attributes to
camelCase
so React can understand it. Imagine if you have 100-200 icons – it would be a daunting task to make them fit to React. - If we suddenly would need to modify the icon in any graphic editor – we would have to revert our "React SVG" to plain SVG code.
- React will process this code. It's redundant in our case; plain HTML works fine.
3. SVG as React Component
This approach is similar to the second one. We can use Webpack loader (like SVGR) to do all "SVG to React" work for us, and the final code might be similar to the following:
import IconChevron from './icon-chevron.svg'
const App = () => <IconChevron />
It seems to be a near-best solution – we can put our SVG in some folder and instantly have React component. Despite that, we cannot pass any custom attributes to this component (like default icon size, color, CSS class).
Developing our approach
We can combine all solutions above to develop the final version:
- Create the
Icon
component to handle all icon-related logic in one place.
- Add
name
property to theIcon
component. - Based on passed
name
perform SVG loading during component rendering. It should be imported as a raw string (raw-loader can help with that) and inserted viadangerouslySetInnerHTML
.
- Apply
currentColor
value to SVG's children tofill
property. It makes possible inheritance ofcolor
property from the parent.
Usage
Just place your SVG in the same folder with Icon.tsx
, pass the SVG's file name to name
property of the component, and you're good to go! Let's say you have search.svg
:
import { Icon } from './Icon'const HomePage = () => {
return (
<div className="home-page">
<Icon name="search" />
</div>
)
}
To change color of the icon just write some styles:
.icon-search
color: lightblue
You can see the demo by the following link: https://merksam.github.io/examples/webpack-react-svg-icons/
Summarize
I believe this approach can be applied to any library or framework because the main idea is to use raw SVG along with currentColor
set on SVG's nested elements, making it library-independent.
Thank you for reading! I would appreciate your feedback so much so we can learn from each other. Together we can make this world better :)