SVG to JSX: The Complete Guide to Using SVG in React (2026)
Scalable Vector Graphics (SVG) are the gold standard for icons, logos, illustrations, and other resolution-independent graphics on the web. When you move to React, however, you cannot simply copy-paste SVG markup into a component and expect it to work. React uses JSX, which is similar to HTML but enforces JavaScript-compatible syntax rules that conflict with several SVG conventions. This guide covers everything you need to know about converting SVG to JSX, from basic attribute renaming to building production-grade icon component libraries.
Why SVG Matters in React Applications
Before diving into the conversion process, it is worth understanding why inline SVG is so popular in React applications compared to alternatives like icon fonts or raster images.
First, SVG is resolution independent. A single SVG file looks crisp on any screen density, from a standard 1x display to a 4K Retina panel, without needing multiple image files. Second, SVG is styleable with CSS. You can change colors, sizes, stroke widths, and even animate individual paths using standard CSS or React's inline styles. Third, SVG is accessible. You can add title and desc elements, ARIA attributes, and role attributes to make icons meaningful to screen readers. Fourth, SVG is small. A typical icon SVG is a few hundred bytes, often smaller than the equivalent PNG and much smaller than shipping an entire icon font for a handful of icons.
When you embed SVG inline as JSX rather than loading it through an <img> tag, you gain full programmatic control. You can conditionally change fill colors based on state, animate paths with libraries like Framer Motion, and respond to click events on individual SVG elements. This is why converting SVG to JSX is such a common task in React development.
The Key Differences Between SVG and JSX
JSX is syntactic sugar for React.createElement() calls. Because it compiles to JavaScript, certain HTML and SVG conventions that are valid in a browser are not valid in JSX. Here are the critical differences you need to handle.
1. class Becomes className
In HTML and SVG, the class attribute assigns CSS classes to elements. In JavaScript, class is a reserved keyword used for class declarations. JSX therefore uses className instead. If you paste SVG with class="icon" into a React component, the compiler will throw an error or silently ignore the attribute.
<!-- SVG -->
<svg class="icon" viewBox="0 0 24 24">...</svg>
{/* JSX */}
<svg className="icon" viewBox="0 0 24 24">...</svg>
2. Kebab-case Attributes Become camelCase
SVG uses many hyphenated attribute names: stroke-width, fill-opacity, stroke-linecap, clip-path, font-size, text-anchor, and dozens more. In JavaScript, a hyphen in a property name would be interpreted as the subtraction operator. JSX therefore requires these attributes in camelCase: strokeWidth, fillOpacity, strokeLinecap, clipPath, fontSize, textAnchor.
<!-- SVG -->
<circle stroke-width="2" fill-opacity="0.5" />
{/* JSX */}
<circle strokeWidth="2" fillOpacity="0.5" />
There are over 60 SVG attributes that need this conversion. Some of the most commonly encountered ones include:
| SVG Attribute | JSX Equivalent |
|---|---|
| stroke-width | strokeWidth |
| stroke-linecap | strokeLinecap |
| stroke-linejoin | strokeLinejoin |
| stroke-dasharray | strokeDasharray |
| stroke-dashoffset | strokeDashoffset |
| stroke-opacity | strokeOpacity |
| fill-opacity | fillOpacity |
| fill-rule | fillRule |
| clip-path | clipPath |
| clip-rule | clipRule |
| font-size | fontSize |
| font-family | fontFamily |
| font-weight | fontWeight |
| text-anchor | textAnchor |
| text-decoration | textDecoration |
| stop-color | stopColor |
| stop-opacity | stopOpacity |
| flood-color | floodColor |
| flood-opacity | floodOpacity |
| color-interpolation | colorInterpolation |
| color-interpolation-filters | colorInterpolationFilters |
| dominant-baseline | dominantBaseline |
| shape-rendering | shapeRendering |
| image-rendering | imageRendering |
| pointer-events | pointerEvents |
3. Inline Style Strings Become JavaScript Objects
In HTML and SVG, the style attribute is a CSS string: style="fill: red; stroke-width: 2". In JSX, the style attribute must be a JavaScript object with camelCased property names and string or number values: style={{ fill: 'red', strokeWidth: 2 }}. Note the double curly braces: the outer pair denotes a JSX expression, and the inner pair is the JavaScript object literal.
<!-- SVG -->
<rect style="fill: #333; stroke-width: 1; opacity: 0.8" />
{/* JSX */}
<rect style={{ fill: '#333', strokeWidth: 1, opacity: 0.8 }} />
4. xmlns Attributes Are Unnecessary
Raw SVG files typically include xmlns="http://www.w3.org/2000/svg" and sometimes xmlns:xlink="http://www.w3.org/1999/xlink". In HTML5 and in React's JSX, these namespace declarations are not required for inline SVG. Removing them keeps your JSX cleaner, though leaving them will not cause errors.
5. xlink:href Becomes xlinkHref
The xlink:href attribute used in older SVGs for referencing gradients, patterns, and filters must be written as xlinkHref in JSX. Similarly, xml:space becomes xmlSpace and xml:lang becomes xmlLang. Note that xlink:href is deprecated in SVG 2 in favor of plain href, so consider updating to href when possible.
6. Self-Closing Tags
JSX requires that elements with no children be self-closed. While browsers are tolerant of <path></path> in SVG, JSX prefers <path />. This applies to all void SVG elements: circle, ellipse, line, path, polygon, polyline, rect, stop, use, and filter primitives.
Building React SVG Icon Components
Once your SVG is converted to JSX, the next step is wrapping it in a reusable React component. A good SVG icon component follows several patterns.
Basic Component Pattern
import React from 'react';
const CheckIcon = (props) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<polyline points="20 6 9 17 4 12" />
</svg>
);
};
export default CheckIcon;
The key patterns here are: using currentColor for stroke or fill so the icon inherits the text color from CSS, accepting and spreading props so consumers can override any attribute, and exporting a named component for clean imports.
TypeScript Component
For TypeScript projects, add proper type annotations to get autocomplete and type checking for all SVG attributes.
import React from 'react';
const CheckIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
{...props}
>
<polyline points="20 6 9 17 4 12" />
</svg>
);
};
export default CheckIcon;
The React.SVGProps<SVGSVGElement> type gives your component all the standard SVG attributes as valid props, including className, style, width, height, viewBox, onClick, and every SVG-specific attribute.
Memoized Component for Performance
If your application renders many icons or re-renders frequently, wrapping icons in React.memo prevents unnecessary re-renders when props have not changed.
import React, { memo } from 'react';
const CheckIcon = memo((props) => {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...props}>
<polyline points="20 6 9 17 4 12" />
</svg>
);
});
export default CheckIcon;
Advanced SVG Patterns in React
Dynamic Colors with Props
Instead of hardcoding colors, accept them as props for maximum flexibility.
const StatusIcon = ({ color = 'currentColor', size = 24, ...rest }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill={color} {...rest}>
<circle cx="12" cy="12" r="10" />
</svg>
);
// Usage
<StatusIcon color="#22c55e" size={32} />
<StatusIcon color="#ef4444" size={16} />
Accessible SVG Icons
For icons that convey meaning, add a title element and appropriate ARIA attributes. For decorative icons, use aria-hidden="true" to hide them from screen readers.
{/* Meaningful icon */}
<svg role="img" aria-labelledby="checkTitle" viewBox="0 0 24 24">
<title id="checkTitle">Completed</title>
<polyline points="20 6 9 17 4 12" />
</svg>
{/* Decorative icon */}
<svg aria-hidden="true" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</svg>
SVG Sprites with Symbols
For applications with many icons, you can define SVG symbols once and reference them with <use>. This reduces bundle size because the same path data is not repeated.
{/* Define symbols (typically in a hidden SVG at the top of your app) */}
<svg style={{ display: 'none' }}>
<symbol id="icon-check" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</symbol>
<symbol id="icon-x" viewBox="0 0 24 24">
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</symbol>
</svg>
{/* Use them anywhere */}
<svg width="24" height="24">
<use xlinkHref="#icon-check" />
</svg>
Common Pitfalls and How to Avoid Them
Forgetting to Convert Style Strings
One of the most common mistakes is leaving inline style as a CSS string. React will warn you in the console: "The style prop expects a mapping from style properties to values, not a string." Always convert style strings to JavaScript objects with camelCased keys.
Missing camelCase Conversions
It is easy to miss less common attributes like color-interpolation-filters (which becomes colorInterpolationFilters) or glyph-orientation-vertical. Using an automated converter tool catches all of these consistently.
Not Spreading Props on the Root SVG
If you create an icon component without {...props} on the root <svg> element, consumers cannot override width, height, className, or any other attribute. Always spread props to maintain composability.
Hardcoded Colors
If your SVG has hardcoded fill or stroke colors like fill="#000000", the icon cannot adapt to different themes or contexts. Replace fixed colors with currentColor so the icon inherits the text color, or accept colors as props.
Build Tools and Automation
While our SVG to JSX converter tool handles one-off conversions, production workflows often integrate SVG transformation into the build pipeline.
SVGR
SVGR is the most popular tool for transforming SVG files into React components at build time. It can be used as a webpack loader, a Vite plugin, a Babel plugin, or a CLI tool. Create React App includes SVGR out of the box, allowing you to import SVG files directly as React components.
Vite Plugin
For Vite-based projects, vite-plugin-svgr provides similar functionality, allowing import { ReactComponent as Logo } from './logo.svg' syntax.
Manual Workflow
For teams that prefer manual control or are converting a batch of SVGs from a design tool, using our browser-based converter is the fastest approach. Paste the SVG, enable the component wrapper with your desired options, copy the output, and save it as a .jsx or .tsx file.
Performance Considerations
Inline SVG adds to your JavaScript bundle size. For applications with hundreds of icons, consider these strategies to keep performance optimal.
- Code splitting: Only import icons that are actually used on each page. Tree-shaking will eliminate unused icon components from the bundle.
- SVG sprites: Define icons as symbols in a single SVG and reference them with
<use>to avoid duplicating path data. - React.memo: Wrap icon components in
React.memoto prevent re-renders when parent components update but icon props have not changed. - Lazy loading: For icons that appear below the fold, use
React.lazyandSuspenseto load them on demand. - External SVG files: For very large SVGs like illustrations, consider loading them as external files with
<img>tags rather than inlining them as JSX.
Testing SVG Components
SVG components can be tested with React Testing Library just like any other component. You can query by role, by title text, or by test ID.
import { render, screen } from '@testing-library/react';
import CheckIcon from './CheckIcon';
test('renders check icon', () => {
render(<CheckIcon data-testid="check" />);
expect(screen.getByTestId('check')).toBeInTheDocument();
});
test('accepts custom className', () => {
render(<CheckIcon className="custom" data-testid="check" />);
expect(screen.getByTestId('check')).toHaveClass('custom');
});
Try the SVG to JSX Converter
Frequently Asked Questions
currentColor, then control the color via the CSS color property on the parent element. Alternatively, pass fill and stroke as props to your React SVG component so consumers can customize colors at the call site. Using currentColor is the most common approach because it integrates naturally with CSS theming.