react-icons vs @radix-ui/react-icons vs heroicons
Icon Library Strategies for React Applications
react-icons@radix-ui/react-iconsheroiconsSimilar Packages:

Icon Library Strategies for React Applications

@radix-ui/react-icons, heroicons, and react-icons are three popular ways to add icons to React projects, but they serve different architectural needs. @radix-ui/react-icons provides a focused set of 15x15 pixel icons designed to work seamlessly with Radix UI primitives. heroicons is the official SVG icon set from the creators of Tailwind CSS, primarily distributed as SVG assets that integrate closely with Tailwind utilities. react-icons acts as a unified aggregator, offering thousands of icons from many different sets (like FontAwesome, Material Design, and more) through a single consistent React API.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
react-icons5,946,48412,50486.2 MB232a year agoMIT
@radix-ui/react-icons2,885,501-3.44 MB-a year agoMIT
heroicons023,374700 kB2a year agoMIT

Icon Library Strategies for React Applications

Adding icons to a React app seems simple, but the choice of library affects your bundle size, design consistency, and maintenance workflow. @radix-ui/react-icons, heroicons, and react-icons take three different approaches to solving this problem. Let's break down how they work in real engineering scenarios.

📦 Installation and Import Patterns

The way you bring icons into your code varies significantly between these packages. This affects how easy they are to use and how much setup they require.

@radix-ui/react-icons uses direct named exports from a single package.

  • You install one package and import any icon directly.
  • No need to know which set the icon belongs to.
// @radix-ui/react-icons
import { ArrowRightIcon } from '@radix-ui/react-icons';

function Button() {
  return <ArrowRightIcon />;
}

react-icons organizes icons by their original source set.

  • You must import from a specific sub-path (like hi for Heroicons or fa for FontAwesome).
  • This keeps tree shaking efficient but requires knowing the source.
// react-icons
import { HiArrowRight } from 'react-icons/hi';

function Button() {
  return <HiArrowRight />;
}

heroicons is primarily an SVG asset library.

  • The official React usage often involves copying the JSX from their website or importing SVG files.
  • This gives you full control but requires more manual work than a direct component import.
// heroicons
// Common pattern: Copy JSX from heroicons.com into your component
function ArrowRightIcon(props) {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" {...props}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
    </svg>
  );
}

🌲 Tree Shaking and Bundle Size

All three libraries support tree shaking, but they achieve it differently. This impacts how much unused code ends up in your final build.

@radix-ui/react-icons is built for automatic tree shaking.

  • Each icon is a separate named export.
  • Bundlers like Webpack or Vite automatically remove icons you don't use.
// @radix-ui/react-icons
// Only ArrowRightIcon is included in the bundle
import { ArrowRightIcon } from '@radix-ui/react-icons';

react-icons relies on ES modules for tree shaking.

  • You must import icons individually, not the whole set.
  • Importing the whole set will bloat your bundle.
// react-icons
// ✅ Good: Only HiArrowRight is included
import { HiArrowRight } from 'react-icons/hi';

// ❌ Bad: Includes all Heroicons
// import * as Hi from 'react-icons/hi';

heroicons depends on how you integrate the SVGs.

  • If you copy JSX, only the used SVG code is in your bundle.
  • If you import SVG files, your bundler must be configured to tree shake assets.
// heroicons
// ✅ Good: Only this SVG code exists in your file
function ArrowRightIcon(props) { /* SVG JSX */ }

// ❌ Bad: Loading all SVGs if using a context loader without care
// import allIcons from './heroicons/all';

🎨 Styling and Customization

Icons often need to change color or size based on context. Each library handles props differently.

@radix-ui/react-icons accepts standard SVG props.

  • You can pass className, width, height, or fill directly.
  • Works naturally with Tailwind or CSS modules.
// @radix-ui/react-icons
<ArrowRightIcon className="w-6 h-6 text-blue-500" />

react-icons also passes props to the underlying SVG.

  • You can style them exactly like regular HTML elements.
  • Size is often controlled via size prop or CSS.
// react-icons
<HiArrowRight className="w-6 h-6 text-blue-500" />
// Or
<HiArrowRight size={24} color="blue" />

heroicons gives you raw SVG control.

  • Since you own the JSX, you can modify any attribute directly.
  • No wrapper props to learn, just standard SVG attributes.
// heroicons
<ArrowRightIcon className="w-6 h-6 text-blue-500" />
// Or modify SVG directly
<svg className="w-6 h-6" fill="none" ...>

🧩 Design System Consistency

Consistency matters when your app grows. Mixing icon styles can make the UI feel disjointed.

@radix-ui/react-icons enforces a strict 15x15 grid.

  • All icons are designed to align perfectly with Radix UI components.
  • Best for apps using Radix primitives like Dialogs or Menus.
// @radix-ui/react-icons
// Consistent visual weight across all icons
<ArrowRightIcon />
<CheckIcon />

react-icons mixes many design languages.

  • You can use Material icons next to FontAwesome icons.
  • Great for variety, but requires discipline to keep things uniform.
// react-icons
// Potential mismatch if not careful
<HiArrowRight /> // Heroicons style
<FaFacebook />   // FontAwesome style

heroicons matches Tailwind CSS perfectly.

  • Designed by the same team to work together.
  • Ideal for projects where Tailwind is the core styling engine.
// heroicons
// Matches Tailwind utility classes naturally
<svg className="stroke-current" ... />

🛠️ Maintenance and Updates

Keeping icons up to date can be a hidden cost. Some libraries make this easier than others.

@radix-ui/react-icons updates via npm.

  • You run npm update and get new icons or fixes.
  • No manual code changes needed.
// @radix-ui/react-icons
// Update via package manager
npm install @radix-ui/react-icons@latest

react-icons also updates via npm.

  • One command updates all icon sets included in the library.
  • Very low maintenance overhead.
// react-icons
// Update via package manager
npm install react-icons@latest

heroicons may require manual updates if copying JSX.

  • If you copy SVG code, you must check for updates manually.
  • If you import SVGs, npm updates work normally.
// heroicons
// If copying JSX, you must manually check for updates
// If using npm package:
npm install heroicons@latest

📊 Summary Table

Feature@radix-ui/react-iconsreact-iconsheroicons
TypeReact ComponentsReact ComponentsSVG Assets
ImportNamed ExportNamed Export (Sub-path)JSX Copy or SVG Import
Tree ShakingAutomaticManual (Per Icon)Depends on Integration
Design15x15 GridMixed SetsTailwind Match
SetupZero ConfigZero ConfigManual or Loader

💡 Final Recommendation

Think about your design system and workflow first.

@radix-ui/react-icons is the best fit if you use Radix UI primitives. It ensures your icons align perfectly with your accessible components without extra work.

react-icons wins when you need variety. If your app requires specific branded icons or you want one import style for everything, this is the most efficient choice.

heroicons is the top choice for Tailwind CSS projects. If you want icons that feel native to Tailwind and don't mind copying JSX or configuring SVG imports, it offers the best visual integration.

Final Thought: All three libraries are solid choices. The right one depends on whether you prioritize design system alignment (@radix-ui/react-icons), variety (react-icons), or Tailwind integration (heroicons).

How to Choose: react-icons vs @radix-ui/react-icons vs heroicons

  • react-icons:

    Choose react-icons if you need access to a wide variety of icon sets without installing multiple packages. It is suitable for projects that require specific branded icons (like social media logos) or when you want a single import pattern for all icons regardless of their source.

  • @radix-ui/react-icons:

    Choose @radix-ui/react-icons if you are already using Radix UI primitives and want icons that match the 15x15 grid system exactly. It is ideal for building accessible, consistent design systems with minimal setup and zero configuration for tree shaking.

  • heroicons:

    Choose heroicons if your project relies heavily on Tailwind CSS and you want icons that match the Tailwind design language perfectly. It is best for teams willing to copy JSX snippets or configure SVG loaders to get exact visual control without extra component wrappers.

README for react-icons

React Icons

React Icons

npm

Include popular icons in your React projects easily with react-icons, which utilizes ES6 imports that allows you to include only the icons that your project is using.

Installation (for standard modern project)

yarn add react-icons
# or
npm install react-icons --save

example usage

import { FaBeer } from "react-icons/fa";

function Question() {
  return (
    <h3>
      Lets go for a <FaBeer />?
    </h3>
  );
}

View the documentation for further usage examples and how to use icons from other packages. NOTE: each Icon package has it's own subfolder under react-icons you import from.

For example, to use an icon from Material Design, your import would be: import { ICON_NAME } from 'react-icons/md';

Installation (for meteorjs, gatsbyjs, etc)

Note This option has not had a new release for some time. More info https://github.com/react-icons/react-icons/issues/593

If your project grows in size, this option is available. This method has the trade-off that it takes a long time to install the package.

yarn add @react-icons/all-files
# or
npm install @react-icons/all-files --save

example usage

import { FaBeer } from "@react-icons/all-files/fa/FaBeer";

function Question() {
  return (
    <h3>
      Lets go for a <FaBeer />?
    </h3>
  );
}

Icons

Icon LibraryLicenseVersionCount
Circum IconsMPL-2.0 license1.0.0288
Font Awesome 5CC BY 4.0 License5.15.4-3-gafecf2a1612
Font Awesome 6CC BY 4.0 License6.5.22045
Ionicons 4MIT4.6.3696
Ionicons 5MIT5.5.41332
Material Design iconsApache License Version 2.04.0.0-98-g9beae745bb4341
TypiconsCC BY-SA 3.02.1.2336
Github Octicons iconsMIT18.3.0264
FeatherMIT4.29.1287
LucideISCv5.1.0-6-g438f572e1215
Game IconsCC BY 3.012920d6565588f0512542a3cb0cdfd36a497f9104040
Weather IconsSIL OFL 1.12.0.12219
DeviconsMIT1.8.0192
Ant Design IconsMIT4.4.2831
Bootstrap IconsMIT1.11.32716
Remix IconApache License Version 2.04.2.02860
Flat Color IconsMIT1.0.2329
Grommet-IconsApache License Version 2.04.12.1635
HeroiconsMIT1.0.6460
Heroicons 2MIT2.1.3888
Simple IconsCC0 1.0 Universal12.14.03209
Simple Line IconsMIT2.5.5189
IcoMoon FreeCC BY 4.0 Licensed006795ede82361e1bac1ee76f215cf1dc51e4ca491
BoxIconsMIT2.1.41634
css.ggMIT2.1.1704
VS Code IconsCC BY 4.00.0.35461
Tabler IconsMIT3.2.05237
Themify IconsMITv0.1.2-2-g9600186352
Radix IconsMIT@radix-ui/react-icons@1.3.0-1-g94b3fcf318
Phosphor IconsMIT2.1.19072
Icons8 Line AwesomeMIT1.3.11544

You can add more icons by submitting pull requests or creating issues.

Configuration

You can configure react-icons props using React Context API.

Requires React 16.3 or higher.

import { IconContext } from "react-icons";

<IconContext.Provider value={{ color: "blue", className: "global-class-name" }}>
  <div>
    <FaFolder />
  </div>
</IconContext.Provider>;
KeyDefaultNotes
colorundefined (inherit)
size1em
classNameundefined
styleundefinedCan overwrite size and color
attrundefinedOverwritten by other attributes
titleundefinedIcon description for accessibility

Migrating from version 2 -> 3

Change import style

Import path has changed. You need to rewrite from the old style.

// OLD IMPORT STYLE
import FaBeer from "react-icons/lib/fa/beer";

function Question() {
  return (
    <h3>
      Lets go for a <FaBeer />?
    </h3>
  );
}
// NEW IMPORT STYLE
import { FaBeer } from "react-icons/fa";

function Question() {
  return (
    <h3>
      Lets go for a <FaBeer />?
    </h3>
  );
}

Ending up with a large JS bundle? Check out this issue.

Adjustment CSS

From version 3, vertical-align: middle is not automatically given. Please use IconContext to specify className or specify an inline style.

Global Inline Styling

<IconContext.Provider value={{ style: { verticalAlign: 'middle' } }}>

Global className Styling

Component

<IconContext.Provider value={{ className: 'react-icons' }}>

CSS

.react-icons {
  vertical-align: middle;
}

TypeScript native support

Dependencies on @types/react-icons can be deleted.

Yarn

yarn remove @types/react-icons

NPM

npm remove @types/react-icons

Contributing

./build-script.sh will build the whole project. See also CI scripts for more information.

Development

yarn
cd packages/react-icons
yarn fetch  # fetch icon sources
yarn build

Add/Update icon set

First, check the discussion to see if anyone would like to add an icon set.

https://github.com/react-icons/react-icons/discussions/categories/new-icon-set

The SVG files to be fetched are managed in this file. Edit this file and run yarn fetch && yarn check && yarn build.

https://github.com/react-icons/react-icons/blob/master/packages/react-icons/src/icons/index.ts

Preview

Note The project is not actively accepting PR for the preview site at this time.

The preview site is the react-icons website, built in Astro+React.

cd packages/react-icons
yarn fetch
yarn build

cd ../preview-astro
yarn start

Demo

The demo is a Create React App boilerplate with react-icons added as a dependency for easy testing.

cd packages/react-icons
yarn fetch
yarn build

cd ../demo
yarn start

Why React SVG components instead of fonts?

SVG is supported by all major browsers. With react-icons, you can serve only the needed icons instead of one big font file to the users, helping you to recognize which icons are used in your project.

Related Projects

Licence

MIT

  • Icons are taken from the other projects so please check each project licences accordingly.