You drop an SVG into a component and the build explodes. You switch to an img tag and now you cannot change its colour. Every tutorial shows a different approach and none of them explain the trade-off. There are seven, and each one is right for something.
How to Use SVG in React: Pick by What You Need
The choice comes down to three questions. Does it need to change colour? How many icons are there? Do you control the build?
| Method | Stylable? | Best for |
|---|---|---|
| Inline JSX | Yes | One icon that never changes |
| img tag | No | Logos and illustrations |
| Imported component | Yes | Most icon sets |
| Sprite sheet | Partly | Hundreds of icons |
| SVGR at build time | Yes | Teams with a design pipeline |
| react-svg at runtime | Yes | Icons fetched from a CMS |
| Data URL | No | CSS backgrounds |
Now the detail on each.
1. Inline SVG in React, Straight in the JSX
Paste the markup into your component and fix the attribute names.
export default function Search() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
);
}
Full CSS control, no build configuration, no extra request. It is the most flexible option available.
The catch is maintenance. Paste four icons into a component and it becomes unreadable, and every design update means re-pasting by hand.
Note strokeWidth, not stroke-width. That renaming is mandatory and our SVG to JSX converter handles it automatically.
2. The SVG img Tag Method, and Why Colours Stop Working
Treat the SVG as a normal image.
import logo from './logo.svg';
<img src={logo} alt="Company logo" width={120} />
Simple, cacheable, and the browser handles decoding off the main thread. For a logo that never changes colour, this is genuinely the right answer.
Here is the limit nobody mentions up front: the browser treats that SVG as a sealed document. Your page CSS cannot reach inside it. currentColor has nothing to inherit from.
So the moment a designer asks for a hover state, you are rewriting it as something else.
3. Import SVG as a Component
The default answer for most projects.
import { ReactComponent as SearchIcon } from './search.svg';
<SearchIcon className="w-5 h-5 text-violet-600" />
You get full styling control and the SVG stays a real file your designers can edit.
The trap: this syntax only works where SVGR is configured. Create React App shipped it by default, so thousands of tutorials assume it exists. Vite needs vite-plugin-svgr; plain webpack needs the loader added.
Get it wrong and you import a file path instead of a component, then spend twenty minutes wondering why React is rendering a string.
4. React SVG Sprite Sheets
One file holds every icon, and each usage references a symbol by id.
<svg><use href="/icons.svg#search" /></svg>
The sprite downloads once and caches. Adding the hundredth icon costs one more reference in the markup.
Two real drawbacks. Sprites cannot be tree-shaken, so unused icons ship anyway. And the use element resolves its reference against the base URL, which breaks in surprising ways inside routed apps.
HTTP/2 removed most of the original argument for sprites. We reach for them now only when the icon count is genuinely large.
5. SVGR in Your Build Pipeline
The tooling behind method three, used deliberately.
SVGR converts SVG files to React components at build time. Point it at a folder, get a component per file, with optional SVGO cleanup along the way.
For a team with designers exporting regularly, this is the correct setup. Nobody hand-converts anything.
The cost is configuration you have to own. We compare the trade-off honestly in SVGR versus online converters.
6. Runtime Loading With react-svg
Fetch the SVG in the browser and inject it into the DOM.
import { ReactSVG } from 'react-svg';
<ReactSVG src="/icons/search.svg" />
Useful when the icon path is not known at build time — user-uploaded logos, icons stored in a CMS, white-label themes.
Everything else about it is worse. Each icon is a network request, there is a flash before it arrives, and it will not render at all during server-side rendering.
Reach for it only when the build genuinely cannot know the file.
7. Data URLs for CSS Backgrounds
Embed the SVG in the stylesheet itself.
No request, and the icon is available the moment CSS parses. For a tiny decorative background this works well.
Same sealed-document limit as the img tag, plus a caching cost — change one CSS rule and every embedded icon downloads again.
If you go this route, percent-encoding beats Base64 for SVG. Our SVG to Base64 encoder produces both and measures which is shorter.
What We Actually Recommend
- One-off icon? Inline it and move on.
- A logo that never recolours? An img tag is fine and cheap.
- An icon set under fifty? Imported components, via SVGR or hand conversion.
- Hundreds of icons? A sprite, accepting the tree-shaking loss.
- Unknown at build time? react-svg, reluctantly.
Building for mobile as well? React Native needs different elements entirely — our SVG to React Native converter handles that swap.
Wrapping Up
Knowing how to use SVG in React is mostly about knowing which limitation you can live with. Styling, caching, bundle size, and build control pull in different directions.
Start with imported components. Move to a sprite only when the icon count justifies it, and use an img tag whenever the icon genuinely never changes.
For the attribute renaming that trips up method one, see why React needs camelCase SVG attributes.
