Logo
Back to Blog
Development August 8, 2026 10 min read

How to Use SVG in React: All Seven Methods Compared

O

OmniWebKit Team

Frontend Engineering

Share:
Article Cover Image

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?

MethodStylable?Best for
Inline JSXYesOne icon that never changes
img tagNoLogos and illustrations
Imported componentYesMost icon sets
Sprite sheetPartlyHundreds of icons
SVGR at build timeYesTeams with a design pipeline
react-svg at runtimeYesIcons fetched from a CMS
Data URLNoCSS 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.

Frequently Asked Questions

Why can I not style an SVG loaded through an img tag?

+
Because the browser treats it as a sealed document. Your page CSS cannot reach inside it, and neither can currentColor. If the icon has to change colour, it must be inline or an imported component.

Does importing an SVG as a component work outside Create React App?

+
Only where SVGR is wired in. Vite needs vite-plugin-svgr, and plain webpack needs the loader configured. The syntax people copy from CRA tutorials silently fails everywhere else.

Why does my imported SVG render as a string like /static/media/icon.svg?

+
You imported the URL rather than the component. Most setups give you the file path by default and require a named ReactComponent import, or a query suffix, to get a component back.

Are SVG sprites still worth using?

+
Less often than they were. HTTP/2 removed most of the request overhead that justified them, and they cannot be tree-shaken. They still win when you need hundreds of icons and only render a few per page.

Why does my sprite break on a page with a base tag?

+
The use element resolves its reference against the base URL, not the current page. A base tag or a history-routed app can send it looking for the sprite in the wrong place. Use an absolute path.

Should I inline SVG directly in JSX or import it?

+
Import once you have more than a handful. Inline markup bloats components and makes design updates painful, since a re-export means re-pasting. Inline is fine for one icon that never changes.

Does inlining SVG hurt my bundle size?

+
Yes, and more than the file size suggests. Inlined markup becomes JavaScript that has to be parsed and executed, which is more expensive per byte than an image the browser decodes off the main thread.

Why does my icon show as a black square in Safari?

+
Usually a missing xmlns attribute on the root element. Chrome forgives it in some contexts and Safari does not, especially inside a data URL. Add the namespace and the square disappears.

Can I lazy-load SVG icons?

+
You can with React.lazy, but it rarely pays. An icon is a few hundred bytes and the extra chunk request costs more than the bytes saved. Lazy-load illustrations, not icons.

What is the fastest method overall?

+
For a small set, imported components win on flexibility and cost almost nothing. For pure raw speed on a page with many identical icons, a sprite still edges ahead because the markup appears once and gets referenced.

Tags

#React#SVG#Icons#Frontend