/blog/create-custom-svg-icons-for-react
Created on Feb 25, 2022 by Bran Hills

Create custom .svg icons for React

This is how I, a designer on a journey to more fully understand my medium of choice (the web), utilized my 2400 Icons in my Next.js website.

I’m new at the modern webdev stuff. I understand HTML and CSS enough to get by, but my last round with object oriented programming was Visual Basic back in 2003 in my Freshman year of college. Today, I’m a designer who desires to ship his own products. So, of course, the first thing I wanted to do was use a custom icon set in my projects.

One of the first things I’ve picked up from my react mentors is to use props for everything. I wanted to figure out a way to represent an icon with a react component and call the icon by name with props.

Surprise, I couldn’t figure out a way to do that. However, I did find a way to change all of my .svg Icon files in to react components, which can work as easily as I want it to, perhaps even easier.

Changing the .svg to .jsx

Set of four arrow icons with two colors
Set of four, two-color icons

Example .svg icon markup

<svg 
    width="24" 
    height="24" 
    viewBox="0 0 24 24" 
    fill="none" 
    xmlns="http://www.w3.org/2000/svg">
<path 
    d="M18.5 12H4" 
    stroke="#3E7BFA" 
    stroke-width="2" 
    stroke-linecap="round" 
    stroke-linejoin="round"
/>
<path 
    d="M13 6.5L18.5 12L13 17.5" 
    stroke="#555770" 
    stroke-width="2" 
    stroke-linecap="round" 
    stroke-linejoin="round"
/>
</svg>

As you can see, there are hex values in place to determine the color of the icons, which we don’t want in case we decide to change the color programatically.

SVGR

I used the SVGR command line interface tool to change my .svg to .jsx

SVGR Landing page screenshot that says transform SVGs into react components, a complete tool box to take advantage of using SVGs in your React applications
SVGR Landing page

From what I understand, this is included in create-react-app and Nextjs, so we can serve up any .svg file as a React component without having to install anything - but what we’re after is the easy functionality of calling the icon and changing the color dynamically.

I also found this nifty youtube tutorial created by user Mykhaylo Ryechkin who explains in depth how to create an icon component library.

SVGR Command Line Tool

If you’re using 2400 icons instead of just a couple, using the CLI was a no-brainer. Install and run the tool with:

npm install --save-dev @svgr/cli

# or use yarn
yarn add --dev @svgr/cli

There’s a ton of options, and to fit my needs I had to play around with the SVGR Playground first, since I’m a visual learner, it helped me understand exactly what the CLI Inputs were doing and would turn my .svg in to.

I didn’t write a new script in my next.config.js file as I wasn’t creating a whole component library to host for anyone else to use, I just needed to transform the directory in to .jsx files. So, I ended up using:

npx svgr --icon --title-prop --replace-attr-values "#3E7BFA=currentColor" --out-dir public/assets/ public/icons

To break this down, the —icon option changed my width and height to 1em by default, which is great, because I’ve learned using Ems to determine the size of an icon will scale the icon up proportionally if the text size is increased.

--title-prop option gives us a title prop and an aria-labelledby prop for accessibility options should we need it.

--replace-attr-values replaces the hex value of ‘#3E7BFA’ with ‘currentColor’, which allows us to use a prop of color={theme.colors.primary} to set the color of the icon.

--out-dir public/icons/ public/assets lets us set the directory where our .svg files are located and set the directory of where we want our React components to go.

import * as React from "react";

const SvgFullArrowRight = ({ title, titleId, ...props }) => (
  <svg
    width="1em"
    height="1em"
    viewBox="0 0 24 24"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    aria-labelledby={titleId}
    {...props}
  >
    {title ? <title id={titleId}>{title}</title> : null}
    <path
      d="M18.5 12H4"
      stroke="currentColor"
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path
      d="m13 6.5 5.5 5.5-5.5 5.5"
      stroke="#555770"
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
);

export default SvgFullArrowRight;

After running the script, you’ll end up with a cloned directory, with all of your .svg files replaced with .jsx files and the spaces in the names of the files are removed. You’ll also notice an extra .jsx file in your directories called index.js.

// @create-index

export { default as FullArrowRight } from './FullArrowRight.js';
export { default as Add } from './Add.js';
export { default as AddAlarm } from './AddAlarm.js';
export { default as AddCall } from './AddCall.js';
export { default as AddCamera } from './AddCamera.js';
export { default as AddCart } from './AddCart.js';

This is the file you’ll want to import in to any react components to use the icon library. You can import it like so:

import * as Icon from '../public/icons/Duotone/Index';

This imports all of the exports from the icon index as a default object. You can access a specific icon by calling the icon import and using the name of the .jsx file together, for example, if I want the FullArrowRight icon to display as a react component:

<Icon.FullArrowRight />

From here, we can set the props of width, height, and color like this: (remember, the default width and height is 1em)

<Icon.FullArrowRight 
    width='1.2em'
    height='1.2em'
    color={theme.colors.primary}
/>

Now I feel like I’m starting to learn more and more about react. I’ve been on this journey for a couple weeks now, chipping away an hour or two at a time and learning by making lots of mistakes.

If you have any tips or tricks I should try, @branhillsdesign on Threads. I’m always down to talk about best practices and learn from anyone ahead of me in the journey.