@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.
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.
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.
// @radix-ui/react-icons
import { ArrowRightIcon } from '@radix-ui/react-icons';
function Button() {
return <ArrowRightIcon />;
}
react-icons organizes icons by their original source set.
hi for Heroicons or fa for FontAwesome).// react-icons
import { HiArrowRight } from 'react-icons/hi';
function Button() {
return <HiArrowRight />;
}
heroicons is primarily an SVG asset library.
// 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>
);
}
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.
// @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.
// 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.
// 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';
Icons often need to change color or size based on context. Each library handles props differently.
@radix-ui/react-icons accepts standard SVG props.
className, width, height, or fill directly.// @radix-ui/react-icons
<ArrowRightIcon className="w-6 h-6 text-blue-500" />
react-icons also passes props to the underlying SVG.
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.
// heroicons
<ArrowRightIcon className="w-6 h-6 text-blue-500" />
// Or modify SVG directly
<svg className="w-6 h-6" fill="none" ...>
Consistency matters when your app grows. Mixing icon styles can make the UI feel disjointed.
@radix-ui/react-icons enforces a strict 15x15 grid.
// @radix-ui/react-icons
// Consistent visual weight across all icons
<ArrowRightIcon />
<CheckIcon />
react-icons mixes many design languages.
// react-icons
// Potential mismatch if not careful
<HiArrowRight /> // Heroicons style
<FaFacebook /> // FontAwesome style
heroicons matches Tailwind CSS perfectly.
// heroicons
// Matches Tailwind utility classes naturally
<svg className="stroke-current" ... />
Keeping icons up to date can be a hidden cost. Some libraries make this easier than others.
@radix-ui/react-icons updates via npm.
npm update and get new icons or fixes.// @radix-ui/react-icons
// Update via package manager
npm install @radix-ui/react-icons@latest
react-icons also updates via npm.
// react-icons
// Update via package manager
npm install react-icons@latest
heroicons may require manual updates if copying JSX.
// heroicons
// If copying JSX, you must manually check for updates
// If using npm package:
npm install heroicons@latest
| Feature | @radix-ui/react-icons | react-icons | heroicons |
|---|---|---|---|
| Type | React Components | React Components | SVG Assets |
| Import | Named Export | Named Export (Sub-path) | JSX Copy or SVG Import |
| Tree Shaking | Automatic | Manual (Per Icon) | Depends on Integration |
| Design | 15x15 Grid | Mixed Sets | Tailwind Match |
| Setup | Zero Config | Zero Config | Manual or Loader |
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).
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.
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.
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.
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.
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';
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>
);
}
You can add more icons by submitting pull requests or creating issues.
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>;
| Key | Default | Notes |
|---|---|---|
color | undefined (inherit) | |
size | 1em | |
className | undefined | |
style | undefined | Can overwrite size and color |
attr | undefined | Overwritten by other attributes |
title | undefined | Icon description for accessibility |
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.
From version 3, vertical-align: middle is not automatically given. Please use IconContext to specify className or specify an inline style.
<IconContext.Provider value={{ style: { verticalAlign: 'middle' } }}>
className StylingComponent
<IconContext.Provider value={{ className: 'react-icons' }}>
CSS
.react-icons {
vertical-align: middle;
}
Dependencies on @types/react-icons can be deleted.
yarn remove @types/react-icons
npm remove @types/react-icons
./build-script.sh will build the whole project. See also CI scripts for more information.
yarn
cd packages/react-icons
yarn fetch # fetch icon sources
yarn build
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
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
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
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.
MIT