SVG to JSX: The Complete Guide to Using SVG in React (2026)

Published on March 27, 2026 by Suvom Das

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 AttributeJSX Equivalent
stroke-widthstrokeWidth
stroke-linecapstrokeLinecap
stroke-linejoinstrokeLinejoin
stroke-dasharraystrokeDasharray
stroke-dashoffsetstrokeDashoffset
stroke-opacitystrokeOpacity
fill-opacityfillOpacity
fill-rulefillRule
clip-pathclipPath
clip-ruleclipRule
font-sizefontSize
font-familyfontFamily
font-weightfontWeight
text-anchortextAnchor
text-decorationtextDecoration
stop-colorstopColor
stop-opacitystopOpacity
flood-colorfloodColor
flood-opacityfloodOpacity
color-interpolationcolorInterpolation
color-interpolation-filterscolorInterpolationFilters
dominant-baselinedominantBaseline
shape-renderingshapeRendering
image-renderingimageRendering
pointer-eventspointerEvents

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.

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

Why do SVG attributes need to be camelCase in React?
React's JSX is compiled to JavaScript function calls. In JavaScript, object property names with hyphens like stroke-width would be interpreted as subtraction (stroke minus width). React therefore requires camelCase equivalents like strokeWidth so the attributes can be passed as JavaScript object properties without syntax errors.
Should I use inline SVG or an img tag in React?
Inline SVG (as JSX) gives you full control over styling, animation, and interactivity. You can change colors with CSS, animate paths, and respond to click events. Using an img tag is simpler but treats the SVG as a static image with no access to internal elements. For icons and interactive graphics, inline SVG is generally preferred. For large illustrations that do not need interactivity, an img tag is more efficient.
How do I make SVG icons accept custom colors in React?
Set the SVG's fill or stroke attribute to 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.
What is the benefit of React.memo for SVG components?
React.memo prevents unnecessary re-renders by memoizing the component output. Since SVG icons are often purely presentational and receive the same props across renders, wrapping them in React.memo can improve performance in applications that render many icons or re-render frequently due to state changes in parent components.
Do I need to remove xmlns from SVG in React?
The xmlns attribute is not required for inline SVG in HTML5 or JSX. React will render the SVG correctly without it. Removing it keeps your JSX cleaner and reduces file size slightly, though leaving it in place will not cause any errors or warnings.