How to Use SVG Icons in React: Components, Props and Best Practices
The practical guide to using SVG icons in React, inline vs import, turning SVGs into reusable components, passing size and colour via props, and accessibility.
React and SVG are a natural match. Because an SVG is just markup, and React is a library for describing markup, you can turn a static icon file into a live, reusable component that accepts props for size, colour and accessibility. This guide walks through the real options (from the quick copy-paste to a clean, prop-driven icon component) and the gotchas that trip people up along the way.
Why put SVG inline in React at all
You could always render an icon with <img src="/icon.svg" />, and sometimes that's the right call. But inlining the SVG directly into your JSX unlocks everything that makes SVG powerful:
- Style it with CSS and props. An inline SVG can inherit
currentColor, respond to hover, and change size without a second HTTP request. - No extra network request. The icon ships inside your component bundle rather than as a separate file to fetch.
- Animate individual parts. You can target specific paths: impossible when the SVG is locked inside an
<img>.
The trade-off is that inlining adds markup to your rendered DOM, so for a huge, complex illustration used once, an <img> may still be better. For the small icons that make up a UI, inline wins.
The gotcha: SVG attributes aren't JSX attributes
You can't paste raw SVG into JSX and expect it to compile. JSX uses camelCase for most attributes, so the XML you copied needs translating:
stroke-widthbecomesstrokeWidthfill-rulebecomesfillRuleclip-pathbecomesclipPathclassbecomesclassNamexlink:hrefbecomesxlinkHref
Convert one icon by hand and you'll quickly see why nobody does this manually for a whole set. Paste your SVG into the SVG-to-React converter and it does the attribute translation for you, emitting a ready-to-use component, with TypeScript typings if you want them. Everything runs in the browser, so your unreleased assets never leave your machine. If your source SVGs came out of a design tool, run them through the SVG optimiser first so you're not converting bloat into a component. Our guide on optimising SVG for the web covers why that matters.
A clean, reusable icon component
The goal is a component you configure with props rather than editing the SVG each time. Here's the pattern most icon libraries follow:
function IconCheck({ size = 24, color = "currentColor", title, ...props }) {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
role={title ? "img" : "presentation"}
aria-hidden={title ? undefined : true}
{...props}
>
{title ? <title>{title}</title> : null}
<path d="M20 6 9 17l-5-5" />
</svg>
);
}
A few things make this good:
sizeprop sets both width and height, so<IconCheck size={32} />just works.colordefaults tocurrentColor, meaning the icon matches surrounding text unless you override it. This is the single most useful habit for icons. It gives you dark-mode and hover support for free.- Spread
...propsso callers can passclassName,onClickorstylethrough to the root<svg>. - Accessibility is handled (more on that below).
Getting colour right with currentColor
The most common frustration is an icon that won't change colour. Usually it's because the SVG has a hardcoded fill="#333" baked into its paths. When you set fill or stroke on a path directly, CSS on the parent can't override it.
The fix: strip hardcoded colours from the paths and let the icon inherit. With stroke="currentColor" (or fill="currentColor"), this works instantly:
.button:hover .icon { color: royalblue; }
No icon-specific CSS needed, the icon follows the text colour of whatever contains it.
Accessibility: don't skip this
An icon component should tell assistive technology whether it means anything.
- Decorative icons (next to a text label that already says "Delete") should be hidden from screen readers:
aria-hidden="true". Announcing them just adds noise. - Meaningful icons (a lone icon button with no visible text) need a label. Add a
<title>element inside the SVG and reference it, or putaria-label="Delete"on the interactive element. The component above switches behaviour based on whether atitleprop is passed.
Getting this right is a genuine quality signal and takes only a prop.
Managing a whole icon set
One component is easy. Forty is a system. A few approaches scale well:
- A single sprite. Define every icon once in a hidden
<svg>and reference each with<use href="#icon-name" />. This deduplicates identical icons and keeps the DOM light. We compare this approach with alternatives in SVG vs icon fonts. - A generated component per icon. Tools in the SVGR family, and our SVG-to-React converter, turn a folder of SVGs into a folder of typed components you import by name:
import { IconCheck } from "@/icons". - A dynamic
<Icon name="check" />. One component that looks up the right paths from a map. Convenient, but be careful it doesn't force you to bundle every icon even when a page uses two.
For most apps, generating one component per icon gives the best mix of tree-shaking, type safety and clarity.
Performance notes
Inlining icons keeps requests down, but watch two things. First, if the same icon appears dozens of times on a page, a sprite with <use> avoids repeating its path data in the DOM. Second, keep the SVGs lean. A converted component is only as small as its source, so optimise before you convert. On the flip side, don't over-engineer: for a handful of icons, plain inline components are perfectly fast.
A few habits that scale
Using SVG icons in React comes down to a few habits: inline the SVG so you can style and animate it, translate the attributes to JSX (let the SVG-to-React converter do it), drive size and colour with props, default to currentColor, and label icons for screen readers. Do that and your icons become a small, consistent, accessible system rather than a pile of one-off image tags, sharp on every screen and easy to restyle as your design evolves.
What the converter automates
The SVG to React converter does the mechanical part of everything above: camelCases the attributes, wires a typed props spread so className and aria-label pass through, and offers TypeScript, memo, forwardRef and React Native variants as toggles, with a live preview of the component it will hand you. The fiddly find-and-replace work this article describes is exactly what it exists to delete from your day. Markup you paste is processed locally.
Sources
- SVG in JSX (React documentation): attribute naming in JSX
- �40� (MDN Web Docs)
Written by
Chandrabhan Shekhawat
Founder of Gigai Kripa Services. Builds the 250+ privacy-first browser tools on this site and writes the guides that go with them.
Never miss a guide
New tools and how-to articles land regularly. Follow along however you like. No inbox required.
Keep reading
svg-tools
Understanding SVG Path Syntax: The d Attribute Demystified
The cryptic d attribute in SVG paths (M, L, C, Q, A, Z) explained command by command, with the absolute vs relative rule and how curves actually work.
6 mins readsvg-tools
SVG Data URIs Explained: Inlining Vectors the Efficient Way
What an SVG data URI is, why URL-encoding beats base64 for vectors, and how to inline SVG into CSS and HTML without an extra request, plus when NOT to inline.
5 mins readsvg-tools
How to Animate SVG: A Beginner's Guide to CSS and SMIL
A friendly introduction to animating SVG: moving and colouring shapes with CSS, the line-drawing trick, SMIL animation, and when to reach for each approach.
6 mins read