No Time Dad

A blog about web development written by a busy dad

Example React Icons Component

You can’t escape using icons these days. They’re everywhere. And there is an almost endless amount of options when it comes to selecting which icon pack to use. Font Awesome is one of the more populate choices, but Material Icons are also a great choice.

Personally, I like creating svg React icons. Not creating them from scratch, but using existing, well designed icons from the web. My favorite choice for svg icons right now is heroicons. They’re clean and simple icons that are easy to use. Their site is also well designed, which shouldn’t come as a surprise since it’s done by the folks at Tailwindcss.

// package.json
...
"react": "^17.0.2",
...
// icons.jsx
import React from 'react';
import * as styles from './styles.module.css';

export const FireSvg = ({ modifier }) => (
  <svg xmlns="http://www.w3.org/2000/svg" className={`${styles.icon} ${modifier}`} viewBox="0 0 20 20" fill="currentColor">
    <path fillRule="evenodd" d="M12.395 2.553a1 1 0 00-1.45-.385c-.345.23-.614.558-.822.88-.214.33-.403.713-.57 1.116-.334.804-.614 1.768-.84 2.734a31.365 31.365 0 00-.613 3.58 2.64 2.64 0 01-.945-1.067c-.328-.68-.398-1.534-.398-2.654A1 1 0 005.05 6.05 6.981 6.981 0 003 11a7 7 0 1011.95-4.95c-.592-.591-.98-.985-1.348-1.467-.363-.476-.724-1.063-1.207-2.03zM12.12 15.12A3 3 0 017 13s.879.5 2.5.5c0-1 .5-4 1.25-4.5.5 1 .786 1.293 1.371 1.879A2.99 2.99 0 0113 13a2.99 2.99 0 01-.879 2.121z" clipRule="evenodd" />
  </svg>
);

export const BadgeCheckSvg = ({ modifier }) => (
  <svg xmlns="http://www.w3.org/2000/svg" className={`${styles.icon} ${modifier}`} viewBox="0 0 20 20" fill="currentColor">
    <path fillRule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
  </svg>
);

export const LightningBoltSvg = ({ modifier }) => (
  <svg xmlns="http://www.w3.org/2000/svg" className={`${styles.icon} ${modifier}`} viewBox="0 0 20 20" fill="currentColor">
    <path fillRule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clipRule="evenodd" />
  </svg>
);
/* styles.module.css */

/* Default icon styles */
.icon {
  width: 38px;
  height: 38px;
}
<div>
  <FireSvg />
  <BadgeCheckSvg />
  <LightningBoltSvg />
</div>

So, here I’m taking the element from heroicons and dropping it into a react component. I give it a base style selector called icon and I allow a modifier string to be passed to the className attribute that changes the default styling as needed. This makes the react icons extremely flexible and resuable.

If I wanted the FireSvg to be slightly smaller and red, I’d just need to create a new css selector in my styles.module.css and pass the name of the selector to the FireSvg component.

Another thing worth mentioning is that when working with svg element in React, it’s important to remember to convert dash deliminated attributes to camelcame. A warning will show up in the console if this isn’t done.

For example: fill-rule should be changed to fillRule and clip-rule should be changed to clipRule.

/* styles.module.css */
...
.icon__red {
  width: 24px;
  height: 24px;
  color: red;
}
<div>
  <FireSvg modifier="icon__red"/>
</div>

The main drawback with this approach is that the modifier selector is tightly coupled to the styles.module.css file imported in icons.jsx. For most projects this is fine, but on larger projects where icons are used in many different places it might become an issue. Overall, I think this a great approach for creating react icons.