SVG, or Scalable Vector Graphics, is a vector graphics image format based on XML. It was developed in the late 90s and was poorly supported until around 2016.
Today, a huge percentage of icon libraries, such as Flaticon, Font Awesome, and Material Icon have full support for SVG. Brands such as X, YouTube, Udacity, and Netflix use SVG for some of their images and icons.
In this article, we will explore the advances of using SVG over other image formats and various ways to implement SVGs in React applications, including their integration, animation, and usage as React components.
There are multiple ways to handle SVGs in React. Let’s explore a few:
One common approach is inline SVG, where the <svg>
element is directly embedded in JSX. This method provides full control over styling, animations, and interactivity. However, it can make the code cluttered, especially when working with complex SVGs.
<img>
tagAnother method is using the <img>
tag to load an external SVG file. This is great for static SVGs like logos that do not require styling or animations. The downside is that SVGs used in <img>
tags cannot be styled with CSS.
For a more React-friendly approach, you can import SVGs as React components using SVGR, a tool that converts SVGs into fully customizable React components. This method is great for dynamic styling, animations, and modifying SVG elements via props.
If you need flexibility, full control over styling and interactivity, inline SVGs or SVGR are great choices. If simplicity is a priority, using an <img>
tag or component import might be the best option.
Editor’s note: This article was last updated by Emmanuel John in April 2025 to include information on SVGR usage, cover SVG utilization on React frameworks such Next.js, Gatsby, and Refine, and troubleshoot common mistakes when using SVGs in React.
Below, we’ll explore various ways to use or render this React SVG logo on a webpage. It’s worth noting that Create React App (CRA) has a built-in configuration for handling SVGs. Some of the examples in this article that require modifying the webpack setup apply only to custom React projects using webpack as a bundler.
You may need different plugins if you don’t use webpack for your custom React project.
<img>
tag for static SVGsIn order to use SVGs or any other image format in the <img>
tag, we have to set up a file loader system in whichever module bundler we’re using. Here, I will show you how to set it up in a few steps if you are already using webpack as your bundler.
If you are using webpack 4, first install the file-loader library with the command $ npm install file-loader --save-dev
. This will install it as a dev dependency.
You can update your webpack configuration file rules with this code:
const webpack = require('webpack'); module.exports = { entry: './src/index.js', module: { rules: [ //... { test: /\.(png|jp(e*)g|svg|gif)$/, use: [ { loader: 'file-loader', options: { name: 'images/[hash]-[name].[ext]', }, }, ], }, ], }, //... };
However, the file-loader library is deprecated if you are using webpack 5; you can use asset modules instead. With asset modules, you can use asset files in your project setup without installing additional loaders. Update the rules field of your webpack configuration file to include the following:
module.exports = { entry: "./src/index.js", module: { rules: [ //... { test: /\.(png|jp(e*)g|svg|gif)$/, type: "asset/resource", }, ], }, //... };
Now you can import your SVG and use it as a variable, like this:
import React from 'react'; {/*images*/} import ReactLogo from './logo.svg'; const App = () => { return ( <div className="App"> <img src={ReactLogo} alt="React Logo" /> </div> ); } export default App;
This method of importing SVGs has a disadvantage as it cannot be styled in an img
element, making it suitable for non-customizable SVGs like logos, unlike other methods.
<svg>
elementWith the same webpack settings above, we can use the <svg>
element by copying and pasting the contents of the .svg
file into our code. Here is a sample use case:
import React from 'react'; const App = () => { return ( <div className="App"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"> <g fill="#61DAFB"> <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/> <circle cx="420.9" cy="296.5" r="45.7"/> <path d="M520.5 78.1z"/> </g> </svg> </div> ); } export default App;
You can likely already see the disadvantages of using this method. When the image is more complex, the SVG file becomes larger, and because SVG is stored in text, we have a whole bunch of text in our code.
SVGs can be imported and used directly as React components in your React code. The image is not loaded as a separate file; rather, it’s rendered along with the HTML. A sample use case would look like this:
import { ReactComponent as Logo} from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <Logo /> </div> ); } export default App;
Although this approach is simple to implement, it has some drawbacks. The imported SVG functions as an image element, not a full-fledged React component, and cannot be customized with props. It’s not suitable for complex SVGs with multiple elements or styles.
Another approach is converting it to a React component before using it in your React application:
const BarIcon = () => { return ( <svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path stroke="currentColor" strokeLinecap="round" strokeWidth="2" d="M5 7h14M5 12h14M5 17h14" /> </svg> ) } function App() { return ( <header className="App-header"> <BarIcon /> </header> ); } export default App;
JSX supports the svg
tag, allowing for the direct copy-paste of SVGs into React components without using a bundler. SVGs are in XML format, similar to HTML, and can be converted to JSX syntax. Alternatively, a compiler can be used instead of manually converting:
export default function App() { return ( <svg className="w-10 h-10 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill={fill} width={width} height={height} viewBox="0 0 24 24"> <path stroke="currentColor" strokeLinecap="round" strokeWidth="2" d="M5 7h14M5 12h14M5 17h14" /> </svg> ); }; export default App;
Inline SVGs offer access to their properties, allowing for customization and style. However, large SVG file sizes may reduce code readability and productivity, so using a PNG or JPEG file is recommended.
SVGR is an awesome tool that converts your SVGs into React components. It now use SVGO v2 for SVG optimization, which no longer supports automatic merging of configurations.
To set it up, first install the package by running the command $ npm install @svgr/webpack --save-dev
. Then, update your webpack configuration rule to use SVGR for SVGs:
const webpack = require('webpack'); module.exports = { entry: './src/index.js', module: { rules: [ //... { test: /\.svg$/, use: ['@svgr/webpack'], }, ], }, //... };
Now you can import SVG images as React components and use them in your code like so:
import React from 'react'; import ReactLogo from './logo.svg'; const App = () => { return ( <div className="App"> <ReactLogo /> </div> ); } export default App;
To transform SVG into React components, SVGR applies several complex transformations, starting with optimizing the SVG using SVGO.
It then transforms HTML into JSX through multiple steps, such as converting the SVG into HAST (HTML AST), then into Babel AST (JSX AST), and further modifying the AST using Babel to rename attributes and adjust values. Next, it wraps the JSX into a React component, converts the Babel AST into code, and finally formats the code using Prettier for a clean and structured output.
Data URLs are URLs prefixed with the data:
scheme, which allows content creators to embed small files inline in documents. This approach enables us to use SVG images like an inline element.
How do you achieve this? First, you’ll need an appropriate loader if you are using webpack. For this use case, I’ll use svg-url-loader
. You can add it to your project by running the command $ npm install svg-url-loader --save-dev
.
Then, update the webpack configuration file rules section with the following:
const webpack = require('webpack'); module.exports = { entry: './src/index.js', module: { rules: [ //... { test: /\.svg$/, use: [ { loader: 'svg-url-loader', options: { limit: 10000, }, }, ], }, ], }, //... };
Now you can import your SVG file and use it in your React component like this:
import ReactLogo from './logo.svg'; const App = () => { return ( <div className="App"> <img src={ReactLogo} alt="React Logo" /> </div> ); }
This usually results in something like this in the DOM:
<img src="data:image/svg+xml,%3csvg..." alt="React Logo" />
Adding SVG markup directly in your React component increases its file size, making it hard to maintain. Despite this limitation, using inline SVG comes with its advantages. You can easily apply CSS styles to the SVG markup when you embed it inline, compared to using the <img>
tag.
To leverage the benefits of embedding SVGs inline without worrying about the maintainability of your component, you can use the react-svg package. It fetches the SVG asynchronously and embeds it inline.
You can install it from the npm package registry like so:
npm install react-svg
You can then import the ReactSVG
component and render it in your React application. The ReactSVG
component takes the URL for your SVG as the value of the src
prop. It also takes several optional props you can look up in the documentation:
import { ReactSVG } from "react-svg"; <ReactSVG src="icon.svg" />
As mentioned in the introduction, one of the benefits of using SVGs over other image formats is that SVGs can be animated. You can animate SVGs using CSS or React animation libraries like Framer Motion and React Spring.
A few things to be aware of:
<svg>
element. Here, I would recommend you go with PNG or JPEGsWhile manually converting SVGs to React components is possible, it takes time and is prone to errors. Fortunately, some different techniques and tools make this procedure easier:
svg
tag can be used to embed SVG code directly within JSX components for simple SVGs. This method works well for static SVGs that don’t need to be dynamically modifiedreact-svg
or react-inlinesvg
for further features and functionalityWhen used as React components, SVGs become excellent tools for creating clean and scalable user interfaces. Effectively managing React SVG icons requires careful consideration for scalability and maintainability, and some strategies include:
HamburgerIcon.js
and NotificationIcon.js
are examples of descriptive names that improve readability and organizationTypeScript allows developers to enforce type safety in React applications, including handling SVG elements and their properties. Adhering to best practices for typing SVG properties is important for preventing runtime errors and ensuring code reliability. This section will explore these best practices and provide examples of passing SVG elements as props to other components.
One technique for typing SVG properties in TypeScript to ensure type safety includes using the SVGProps
type that React provides to type SVG-related props correctly. This guards against type errors and guarantees that the right props are supplied to SVG elements:
Another technique involves defining a custom interface that encompasses all relevant SVG properties, extending built-in types for specific attributes:
interface SvgProps { fill?: string; stroke?: string; width?: number; height?: number; // Add other relevant SVG attributes here }
Finally, consider exploring third-party libraries like react-svg or SVGR for pre-defined type definitions for SVG manipulation within React.
Now, let’s see how to provide SVG elements as props to other components in TypeScript:
// Define a component that accepts SVG element as a prop interface Props { svgElement: React.ReactElement<React.SVGProps<SVGElement>>; } const SVGWrapper: React.FC<Props> = ({ svgElement }) => ( <div> {svgElement} </div> );
Here we create an interface Props for the SVGWrapper
component that accepts svgElement
props of the type React.ReactElement<React.SVGProps<SVGElement>>
. The SVGWrapper
component renders the svgElement
that it gets.
In the App
component, we can now pass instances of our SVG icons and components as svgElement
props to SVGWrapper
:
import { BarIcon } from './BarIcon'; export default function App() { return ( <div className="App"> <SVGWrapper svgElement={<BarIcon fill="#fff" className="w-10 h-10 text-gray-800 dark:text-white" />} /> </div> ); }
This way, you can pass SVG elements as props to other components in TypeScript.
interface BarProps { fill?: string; width?: number; height?: number; className?: string; } export const BarIcon = ( { fill, width = 20, height = 20, className, }: BarProps ) => { return ( <svg className={className} aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill={fill} width={width} height={height} viewBox="0 0 24 24"> <path stroke="currentColor" strokeLinecap="round" strokeWidth="2" d="M5 7h14M5 12h14M5 17h14" /> </svg> ) }
The component defines an interface BarProps
, which allows for the specification of optional props like width, height, and fill color, and then renders the SVG code using the path element.
Using this method, the SVG code is passed directly as a string prop. For instance, consider this:
import React from "react" interface ButtonProps { onClick: () => void; svg: string; // Prop for the SVG code } const Button: React.FC<ButtonProps> = ({ onClick, svg }) => ( <button onClick={onClick}> <div dangerouslySetInnerHTML={{ __html: svg }} /> </button> ); const App = () => { const svgString = "<svg width='100' height='100'><circle cx='50' cy='50' r='40' stroke='black' strokeWidth='3' fill='red' /></svg>"; return ( <div> <Button onClick={() => console.log('Svg')} svg={svgString} /> </div> ); }; export default App;
This example demonstrates using the ButtonProps
interface to define props for the Button
, which takes a string property svg
and onClick
as a prop. The component renders the SVG using dangerouslySetInnerHTML
, assigning it to the __html
key, bypassing React’s XSS protection.
It’s crucial to ensure the SVG string is safe to render, as it could pose a security risk if it contains untrusted content. Proper use of dangerouslySetInnerHTML
can prevent cross-site scripting attacks. In App
, we define an SVG string and pass it to Button
as a prop.
To ensure reusability and maintain a single source of truth for SVG code, create a separate component for multiple uses of the same SVG with different styles. If it is only needed once or has a simple SVG, pass the SVG string as a prop.
While SVGs are lightweight and scalable, these techniques can improve performance, especially in complex graphics or animations:
React.memo
for static SVG componentsIf an SVG component doesn’t change often, wrap it with React.memo()
to prevent unnecessary re-renders:
import React from 'react'; const Logo = React.memo(() => ( <svg width="100" height="100"> <circle cx="50" cy="50" r="40" stroke="black" strokeWidth="3" fill="red" /> </svg> )); export default Logo;
SVGR transforms SVGs to optimized and lightweight React components. You can also use SVGO (SVG Optimizer) to reduce SVG file sizes by removing redundant attributes, metadata, and comments.
If your app includes multiple or complex SVGs, lazy loading helps defer their loading until needed, reducing initial page load time:
import React, { lazy, Suspense } from 'react'; const LazySVG = lazy(() => import('./LargeSVG')); const App = () => ( <Suspense fallback={<div>Loading...</div>}> <LazySVG /> </Suspense> );
<title>
and <desc>
For inline SVGs, use <title>
and <desc>
elements to provide additional context and role="img"
and aria-label
attributes for meaningful descriptions. This will improve the user experience for screen readers and assistive technologies
React frameworks, like Next.js, Gatsby, and Refine, offer various ways to handle SVGs efficiently, with some methods being similar across them.
Handling SVGs in Gatsby projects can be done in multiple ways. Using gatsby-plugin-svgr
to import SVGs as React components is the most efficient way, as it allows better styling and animation of SVGs.
To use SVGs as React components, install gatsby-plugin-svgr
:
npm install gatsby-plugin-svgr
Then configure it by adding the plugin to gatsby-config.js
:
module.exports = { plugins: ['gatsby-plugin-svgr'], };
Now you can use it in your components like this:
import React from 'react'; import Logo from '../assets/logo.svg'; // SVG as a React component const Header = () => ( <header> <Logo width={100} height={100} /> <h1>About us</h1> </header> ); export default Header;
You can also use SVGs as static image files with the <img>
tag, or inline SVG code directly for full customization.
To display an SVG as a static image, you can import it directly:
import React from 'react'; import logo from '../assets/logo.svg'; const Header = () => ( <header> <img src={logo} alt="Logo" /> </header> ); export default Header;
Next.js supports importing SVGs as React components using @svgr/webpack
.
To use SVGs as React components in Next.js, install @svgr/webpack
:
npm install @svgr/webpack
Next, update next.config.js
:
const nextConfig = { webpack(config) { config.module.rules.push({ test: /\.svg$/, use: ['@svgr/webpack'], }); return config; }, }; module.exports = nextConfig;
Now you can use it in your components like this:
import React from 'react'; import Logo from '../assets/logo.svg'; // SVG as a React component const Header = () => ( <header> <Logo width={100} height={100} /> <h1>My Next.js Site</h1> </header> ); export default Header;
You can also use react-svgr playground to generate React components from your SVG code by pasting the SVG code in the playground, then copying the generated React components into your Next.js project.
Handling SVGs in Refine projects follows a similar approach to handling SVGs in React. Refine is a React-based framework for building CRUD-heavy web applications like admin panels, dashboards, and internal tools easily.
SVGO optimizes SVG files by removing metadata, comments, and unnecessary attributes, reducing file size while maintaining visual quality. It minifies paths, making the SVG more efficient and lightweight.
You can optimize SVGs in any React frameworks with SVGO:
npm install svgo svgo input.svg -o output.svg
Or use an online SVG optimizer like SVGOMG.
Here are some common mistakes to avoid when using SVGs in React:
<img>
tags for dynamic or styled SVGs — If you need to customize an SVG with CSS or React props, it’s better to use inline SVGs or import them as componentsYou’re probably more familiar with image formats like JPEG, GIFs, and PNG than you are with SVG. However, there are many reasons why you’d want to use SVG over these other formats:
fill
instead of color
. You can also style SVG with CSS. Likewise, because SVGs are DOM-like, they can be created, edited, and animated with any text editorSVGs make up a significant proportion of images on the web today. As highlighted above, SVGs have smaller file sizes than other image formats. You can resize them without losing image quality, and they are animatable.
Though its usage is straightforward with HTML, you need additional tools and configuration to start using SVG in frontend frameworks like React. Most of the popular React project starter toolsets, like Create React App, Vite, and Astro, come with out-of-the-box configurations for handling static assets such as images, including SVGs.
As mentioned in this article, Create React App uses the SVGR webpack loader, @svgr/webpack
, under the hood. Therefore, you can import an SVG with an import
statement and render it in your application. You can also inline the SVG markup. However, rendering SVGs inline can make your components hard to maintain.
For a custom React project that uses webpack as a bundler, you can configure the @svgr/webpack
loader to load SVGs similar to Create React App.
As you use SVGs, it is worth mentioning that complex images can have large SVG files, especially if you want to inline the SVG. Though most popular modern browsers fully support SVGs, some browsers, especially mobile browsers, do not have full support for certain SVG features.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowExplore the MUI Grid system in depth, including updates from MUI v5, and learn how to build responsive grid layouts.
Build a progressive web app using Rust, WebAssembly, SurrealDB, and Nostr with local encryption and fast storage.
Discover how AI code generation works and explore top artificial intelligence coding tools, benefits, and real-world use cases.
Vibe coding is taking the dev world by storm. Break down what it actually means, how the term became popularized, and why it’s catching on.
12 Replies to "A guide to using SVGs in React"
Looks like a lot of editing of Webpack. What’s the best way to use SVG’s without ejecting?
Great article! help me a lot, thanks!
I tried this, but the SVG doesn’t show when using an image tag. I don’t know what I am missing. I installed file-loader, too.
Great article! One usage not mentioned above, using as inline background image:
.elem {
background-image: url(‘data:image/svg+xml, ……’);
}
I second, this is a great article!
Would also like to add the the object tag can be used (…)
But, more important – this article does not relate the fact that some of the methods listed here inline the SVG into the DOM – which allows developers to use CSS and JS to manipulate the SVG which is amazing !
You can use something like react-app-rewired to provide access to a webpack config file without ejecting.
“export ‘ReactComponent’ (imported as ‘ReactLogo’) was not found in ‘../static/images/icon/svg/feather–white.svg’
i go this error messages after using ReactComponent step, what should i do?
If you’re using CRA just import it as a component like in the example. All the SVGR business is handled for you already
“Then we update our Webpack configuration rule to use SVGR for SVGs”. What file is that? With witch name I need to create it?
“ With this, we can already see the disadvantage of using this method, when the image is more complex the SVG file becomes larger and since SVG is stored in text, that means we have a whole bunch of text in our code.”
What are the disadvantages? Is it solely the amount of text in the code? Or is there another disadvantage?
Thanks for sharing mate! Using SVG as a component worked like dream for me. One cool thing is that it creates an inline SVG which to which we can pass props such as className and control its presentation that way.
I use SVG over raster images where possible because of flex box designs, they look good at all screen sizes. I don’t think that “Passing as an SVG string” is a good idea, But having said that it could be possible to create a file with lots of SVG strings then just import them directly from a Module as a const.