const
function()
=>
import
async
return
useState
npm
git
docker
api
console.log
React
Node.js
10110100
01101011
11001010
01011100
10010110
01110001
11010100
00101101
10110010
01001110
Skip to main content
Hero image for Handling Icons in React: Best Practices

Handling Icons in React: Best Practices

Learn how to efficiently manage and automate your SVG icon workflow in React. This guide covers using @svgr/cli to create a scalable and type-safe icon system.

Sean Yasnogorodski
3 min read 655 words RSS

Throughout my experience developing websites with React, I frequently encountered challenges with icons (especially those not sourced from libraries). One key question was: How can I handle my icons more efficiently in code?

Why I Switched to SVGs

Initially, I used PNG and JPEG files for icons, but quickly realized their limitations. Switching to SVG files offered several advantages:

  • Scalability: SVGs can scale without losing quality.
  • Faster Loading: SVG files are lightweight, improving load times.
  • CSS Styling: SVGs can be easily styled directly in CSS.

Creating Icon Components

After adopting SVGs, I structured my icon components like this:

export const ExampleIcon: React.FC = () => {
  return (
    <svg>
      { /* svg code here */ }
    </svg>
  );
};

While this worked, I wanted more flexibility in styling and leveraging React’s component power. To achieve that, I added props to my icon components:

export const ExampleIcon: React.FC<SVGProps<SVGSVGElement>> = (props) => {
  return (
    <svg {...props}>
      { /* svg code here */ }
    </svg>
  );
};

This allows us to pass all standard svg element props to our icons.

Organizing Icons in React

To keep my icons organized, I created an icons folder and added a new component whenever I needed a new icon. This method worked for a while, but I wondered—is there a more efficient approach?

Discovering @svgr/cli

After researching best practices, I came across @svgr/cli, a game-changing tool for handling SVGs in React. This CLI tool automatically generates React components from SVG files, saving time and improving maintainability.

###Generating Icon Components Automatically Instead of manually creating icon components, I could now run a single command to generate them:

npx @svgr/cli icons/svgs --out-dir icons/components --typescript

This command converts all SVG files in the svgs folder into TypeScript React components, placing them in the icons/components folder.

Building a Flexible Icon Component

To streamline the use of icons, I built a reusable Icon component. Here’s the folder structure I used:

src/
  components/
    icons/
  svgs/
  types/
  • components/icons/: Contains generated icon components.
  • svgs/: Stores raw SVG files.
  • types/: Holds TypeScript types, including icon-type.ts.

Step 1: Define Icon Type

In src/types/icon-type.ts, I defined the type for our icon components:

import type * as Icons from '../components/icons';

export type IconType = keyof typeof Icons;

This type ensures that IconType corresponds to the names of the generated components, such as Logo for a Logo.tsx component.

Step 2: Create the Icon Component

Next, I created the Icon.tsx file in src/components/:

import React, { type SVGProps } from 'react';
import type { IconType } from '../types/icon-type';
import * as Icons from './icons';

export type IconProps = SVGProps<SVGSVGElement> & {
  icon: IconType;
};

export const Icon: React.FC<IconProps> = ({ icon, ...props }) => {
  const Component = React.createElement(Icons[icon], props);

  return (
    <span className="custom-icon">
      {Component}
    </span>
  );
};

This component dynamically renders the appropriate icon based on the icon prop. For instance, to display the Logo icon, you would use:

export const TestComponent: React.FC = () => {
  return (
    <div>
      <Icon icon="Logo" />
    </div>
  );
};

Step 3: Styling the Icons

To ensure icons inherit the current text color, add the following to your global CSS file:

.custom-icon path, .custom-icon rect {
  stroke: currentColor;
}

Automating Icon Generation

To simplify the process, I added the following script to my package.json file:

"icons:generate": "npx @svgr/cli src/svgs --out-dir src/components/icons --typescript"

The Final Flow

Whenever you need to add a new icon to your project, simply:

  1. Place the SVG file in the svgs folder.
  2. Run npm run icons:generate.
  3. Use the new icon by referencing it in the <Icon/> component with autocomplete support for icon names.

I hope this article helps you handle icons more effectively in your React projects. Feel free to ask any questions — I’d love to help! 😊