When I first started working with React, I used libraries like React Icons or Bootstrap Icons to manage my icons.
But problems quickly emerged, the first problem is not all of these packages support tree shaking. Without tree shaking, when you build your site, all the icons from the library will be included with your build rather than just the ones you use.
The second problem is these libraries can be hard to setup and manage. So what's a better way? Let me show you. If you're new to React you might not know this but in fact you can use svg icons directly as React components. So how would we do that?
Creating a Component
Take this SVG icon (via Hero Icons)
This SVG icon has the following code:
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path d="M12 14l9-5-9-5-9 5 9 5z" />
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
</svg>
The first thing you will want to do is remove the xmlns
attribute, as it's not used by React when rendering the SVG. Additionally you need to replace the class
attribute with className
to make it compliant with React. Your SVG will now look like this:
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path d="M12 14l9-5-9-5-9 5 9 5z" />
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
</svg>
Now you're ready to create a React component. I suggest creating a functional component.
import React from "react";
export const AcademicIcon = () => {
return (
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path d="M12 14l9-5-9-5-9 5 9 5z" />
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222"
/>
</svg>
);
};
At this point you're ready to use the component! You can use it as is in other react components like so:
import React from 'react'
import { AcademicIcon } from './AcademicIcon.js'
export const App = () => {
return (
<div>
<AcademicIcon />
</div>
)
}
Adding Props
One benefit of using SVG's as React components is you can add props to it just like you would to any other component. Lets add some props to our AcademicIcon
component to make it more flexible.
import React from "react";
export const AcademicIcon = ({ className = "h-6 w-6", fill = "none", stroke = "currentColor", stokeWidth = 2}) => {
return (
<svg className={className} fill={fill} viewBox="0 0 24 24" stroke={stroke}>
<path d="M12 14l9-5-9-5-9 5 9 5z" />
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={strokeWidth}
d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222"
/>
</svg>
);
};
Now in this final version we moved className
, fill
, stroke
and strokeWidth
to a prop and gave it a default of the original value. Now you can call your icon with props:
import React from 'react'
import { AcademicIcon } from './AcademicIcon.js'
export const App = () => {
return (
<div>
<AcademicIcon
className="h-12 w-12"
fill="red"
strokeWidth={3}
/>
</div>
)
}
Because all the props have defaults, you can declare the icon with all the props, some of them or none of them! With this method you are also only loading the icons you are using, no wasteful extra code at build time!
If you enjoyed this post check out my other posts on my blog. You should also check out my latest project: Awesome Devtools
Top comments (2)
Very insightful thank you !!
Iconify is one of the best solutions I've ever seen.