SVG icons are the standard choice for modern React applications. Whether you are building a dashboard, SaaS product, portfolio, or landing page, icons play a critical role in improving usability, navigation, and visual clarity.
Unlike traditional image formats like PNG or JPG, SVG (Scalable Vector Graphics) icons are lightweight, resolution-independent, and fully customizable using CSS and JavaScript.
In this guide you will learn how to use SVG icons in React step by step, covering different methods, best practices, performance optimization tips, and common mistakes to avoid.
Why Use SVG Icons in React?
Before diving into implementation, it is important to understand why SVG icons are preferred in modern frontend development over older alternatives like PNG sprites and icon fonts.
SVG icons scale perfectly across all screen sizes and pixel densities without losing quality. This makes them ideal for responsive web design where your UI needs to look sharp on everything from a budget Android phone to a 4K monitor. A PNG icon that looks fine at 24px will appear blurry and pixelated at 48px — an SVG icon will look identical at any size.
SVG files are also significantly smaller than raster image files for simple graphics like icons. A typical icon is between 0.5kb and 2kb as an SVG, compared to 3kb to 10kb as a PNG with multiple size variants. When you have 20 or 30 icons on a page, this difference compounds into meaningful performance improvements.
Perhaps most importantly for developers, SVG icons integrate directly into React components as JSX. This means you can control their size, color, and stroke width using props, apply Tailwind CSS classes, respond to hover states, and even animate them — all without leaving your component code.
The Three Methods for Using SVG Icons in React
There are three main approaches to using SVG icons in React. Each has its place depending on your use case.
Method 1: Using an Icon Library (Recommended for Most Projects)
This is the easiest, most scalable, and most maintainable approach. Icon libraries like Lucide, Heroicons, and Tabler provide hundreds or thousands of professionally designed icons as typed React components.
Install Lucide Icons — the most popular choice for React in 2026:
npm install lucide-react
Then import and use icons directly in your components:
import { Camera, User, Bell, Settings } from 'lucide-react'
export default function Navbar() {
return (
<nav>
<Bell size={24} />
<Settings size={24} />
<User size={24} />
</nav>
)
}This method is recommended for most projects because icons are tree-shakable so only the icons you import end up in your production bundle, you get full TypeScript autocomplete in VS Code, the design is consistent across all icons, and maintenance is handled by the library team rather than you.
Method 2: Inline SVG
You can paste SVG code directly inside your React JSX. This gives you complete control over every aspect of the icon.
export default function CustomIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
)
}Use this method when you need a completely custom icon that no library provides, when you need to animate specific parts of an icon using CSS or JavaScript, or when a designer has provided custom SVG assets for your brand.
Method 3: Importing SVG as a React Component
Next.js and Create React App both support importing SVG files directly as React components. This is useful for custom brand assets like logos.
import Logo from './logo.svg'
export default function Header() {
return (
<header>
<Logo width={120} height={40} />
</header>
)
}This approach works well for logos and complex brand illustrations but is not ideal for UI icons where you need many variations at different sizes and colors.
How to Customize SVG Icons in React
The ability to customize icons with props is one of the most powerful features of modern icon libraries. Here is how to control the most common properties.
Controlling size — pass a number in pixels:
<Camera size={16} /> // small
<Camera size={24} /> // default
<Camera size={48} /> // largeControlling color — use any valid CSS color value:
<Camera color="#6366f1" /> <Camera color="red" /> <Camera color="var(--brand-color)" />
Controlling stroke width — thinner strokes feel more elegant, thicker strokes feel bolder:
<Camera strokeWidth={1} /> // thin, elegant
<Camera strokeWidth={2} /> // default
<Camera strokeWidth={3} /> // bold, heavyUsing Tailwind CSS classes — icons accept className and inherit the text color:
<Camera className="h-6 w-6 text-blue-500" /> <Camera className="h-4 w-4 text-gray-400 hover:text-gray-600" />
Using SVG Icons in Next.js
SVG icons from all major libraries work perfectly in Next.js App Router with both Server Components and Client Components. No special configuration is required.
// app/page.tsx — Server Component, works fine
import { ArrowRight, Star, Github } from 'lucide-react'
export default function HomePage() {
return (
<main>
<h1>Welcome to my app</h1>
<a href="/docs">
Get started <ArrowRight size={16} />
</a>
</main>
)
}The reason icons work in Server Components is that they are pure SVG output with no browser-only APIs, React context, or client-side state. They render to static HTML on the server without any issues.
Performance Best Practices
SVG icons are lightweight by default, but these practices will keep your application fast as it grows.
Always import icons individually rather than the entire library. The wrong way is to write import star as Icons from lucide-react. The right way is to import specific icons by name. With proper individual imports, each icon adds approximately 0.5kb to 1kb to your bundle. Using 20 icons adds roughly 15kb total — negligible for any modern web application.
Avoid dynamically importing different icons based on string names unless absolutely necessary. Dynamic imports prevent tree-shaking and can significantly increase bundle size.
For very large applications with hundreds of unique icons, consider code-splitting icon-heavy components using React.lazy so icons only load when the component that uses them is rendered.
Accessibility for SVG Icons
Icons used purely for decoration should be hidden from screen readers. Icons that convey meaning should have appropriate labels.
// Decorative icon — hide from screen readers <Camera aria-hidden="true" /> // Meaningful icon — provide a label <button aria-label="Take photo"> <Camera aria-hidden="true" /> </button> // Icon with visible text — hide the icon <button> <Camera aria-hidden="true" /> <span>Take photo</span> </button>
SVG Icons vs PNG Icons
SVG is the clear winner for UI icons in modern React applications. Here is a direct comparison across the properties that matter most.
Scalability — SVG scales perfectly at any size, PNG becomes blurry when scaled up beyond its native resolution.
File size — SVG is typically 0.5kb to 2kb per icon, PNG requires multiple files for different resolutions (1x, 2x, 3x).
Customization — SVG color, size, and stroke can all be changed with CSS or props, PNG cannot be restyled without a new file.
Dark mode support — SVG icons inherit CSS color so they adapt automatically to dark mode, PNG icons require separate dark mode versions.
Animation — SVG icons can be animated using CSS or JavaScript, PNG icons cannot.
The only case where PNG might still be preferable is for complex illustrations or photographs used as decorative elements — not for UI icons.
Which Icon Library Should You Use?
For most React and Next.js projects in 2026, here is a simple decision guide.
Use Lucide Icons if you want the best balance of icon count, design quality, TypeScript support, and active maintenance. It is the default recommendation for new projects.
Use Heroicons if you are already using Tailwind CSS. The design language matches Tailwind UI components perfectly and the integration is seamless.
Use Tabler Icons if you need the largest possible selection — 5,500+ icons covering highly specialized categories that smaller libraries do not have.
Use Phosphor Icons if your design requires multiple weights or duotone icons for a premium visual effect.
Common Mistakes to Avoid
Importing the entire library instead of individual icons is the most common and most damaging mistake. It can add hundreds of kilobytes to your production bundle unnecessarily.
Mixing icons from multiple different libraries on the same page creates visual inconsistency. Icons from different libraries have different stroke widths, corner radii, and design philosophies — they rarely look good together.
Ignoring accessibility by not adding aria-hidden to decorative icons or aria-label to icon-only buttons makes your application difficult for screen reader users.
Using fixed pixel colors instead of currentColor or CSS variables means your icons will not adapt to dark mode or theme changes automatically.