Handling Icons in React: Best Practices

seanyasno

Sean Yasnogorodski

Posted on October 3, 2024

Handling Icons in React: Best Practices

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode
  • 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;
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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! 😊

💖 💪 🙅 🚩
seanyasno
Sean Yasnogorodski

Posted on October 3, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Next.js ready to go
webdev Next.js ready to go

February 9, 2023