DevToolBoxFREE
Blog

SVG to React Component: The Complete Guide to Converting SVG for React

8 min readby DevToolBox

Converting SVG to React components is a critical skill for modern frontend development. SVG (Scalable Vector Graphics) offers resolution-independent graphics that look crisp on every screen, and React provides the component model to make them reusable and interactive. This comprehensive guide covers everything from manual conversion techniques to automated tooling, accessibility best practices, and performance optimization strategies for using SVG in your React applications.

Convert SVG to JSX instantly with our free online tool.

Why Convert SVG to React Components?

Using SVG directly as React components gives you several advantages over traditional approaches like <img> tags or CSS background images. You gain full control over styling through props and CSS-in-JS, the ability to animate individual paths with CSS or libraries like Framer Motion, dynamic theming support (light/dark mode), and tree-shaking so unused icons are excluded from your bundle.

React treats JSX elements as first-class citizens, so SVG components can accept props, respond to events, and participate in the component lifecycle just like any other React element. This makes SVG-based icons, illustrations, and charts far more powerful than static image files.

The main challenge is that raw SVG uses HTML attributes (like class, fill-rule, clip-path) that must be converted to their JSX equivalents (className, fillRule, clipPath). This guide shows you how to handle this conversion reliably.

Method 1: Manual SVG to React Conversion

For a single icon or simple SVG, manual conversion is straightforward. Here is the step-by-step process:

  1. Copy the raw SVG markup from your design tool (Figma, Sketch, Illustrator) or SVG file.
  2. Replace class with className.
  3. Convert hyphenated attributes to camelCase: fill-rule becomes fillRule, stroke-width becomes strokeWidth, clip-path becomes clipPath, etc.
  4. Convert xlink:href to xlinkHref (or remove it for modern SVG).
  5. Self-close tags without children: <path ... /> instead of <path ...></path>.
  6. Wrap in a React component function and export it.

Here is a before-and-after example showing the conversion of a simple checkmark icon:

Raw SVG (before conversion)

<!-- Raw SVG from a design tool -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
     viewBox="0 0 24 24" class="icon-check"
     fill="none" stroke="currentColor" stroke-width="2"
     stroke-linecap="round" stroke-linejoin="round">
  <polyline points="20 6 9 17 4 12"></polyline>
</svg>

React Component (after conversion)

import React from 'react';

interface CheckIconProps {
  size?: number;
  color?: string;
  className?: string;
}

const CheckIcon: React.FC<CheckIconProps> = ({
  size = 24,
  color = 'currentColor',
  className = '',
}) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width={size}
    height={size}
    viewBox="0 0 24 24"
    className={`icon-check ${className}`}
    fill="none"
    stroke={color}
    strokeWidth={2}           // was stroke-width
    strokeLinecap="round"     // was stroke-linecap
    strokeLinejoin="round"    // was stroke-linejoin
    role="img"
    aria-label="Checkmark"
  >
    <polyline points="20 6 9 17 4 12" />
  </svg>
);

export default CheckIcon;

Common SVG Attribute Conversions

HTML Attribute        JSX Equivalent
─────────────────────────────────────────
class                 className
fill-rule             fillRule
clip-path             clipPath
clip-rule             clipRule
fill-opacity          fillOpacity
stroke-width          strokeWidth
stroke-linecap        strokeLinecap
stroke-linejoin       strokeLinejoin
stroke-dasharray      strokeDasharray
stroke-dashoffset     strokeDashoffset
stroke-miterlimit     strokeMiterlimit
stroke-opacity        strokeOpacity
font-size             fontSize
font-family           fontFamily
text-anchor           textAnchor
text-decoration       textDecoration
dominant-baseline     dominantBaseline
alignment-baseline    alignmentBaseline
xlink:href            xlinkHref (deprecated)
xml:space             xmlSpace

Method 2: Automated Conversion with SVGR

SVGR is the industry-standard tool for converting SVG files into React components. It powers the SVG handling in Create React App, Next.js, and Vite. SVGR handles all attribute transformations, adds proper TypeScript types, and can optimize SVG with SVGO in the same pipeline.

You can use SVGR in multiple ways: as a CLI tool, a webpack/Vite plugin, or programmatically in Node.js:

SVGR CLI

# Install SVGR
npm install -D @svgr/cli

# Convert a single SVG file to a React component
npx @svgr/cli --icon --typescript icon.svg

# Convert an entire directory of SVGs
npx @svgr/cli --icon --typescript --out-dir src/components/icons src/assets/svg/

# With SVGO optimization included
npx @svgr/cli --icon --svgo --typescript icon.svg

SVGR with webpack (React/Next.js)

// next.config.js (Next.js example)
module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: [
        {
          loader: '@svgr/webpack',
          options: {
            svgo: true,
            svgoConfig: {
              plugins: [
                { name: 'removeViewBox', active: false },
                { name: 'removeDimensions', active: true },
              ],
            },
            titleProp: true,    // adds title prop for a11y
            typescript: true,   // generates TypeScript
          },
        },
      ],
    });
    return config;
  },
};

// Usage in your component:
import ArrowIcon from './arrow.svg';

function Button() {
  return (
    <button>
      <ArrowIcon width={20} height={20} title="Navigate" />
      Next
    </button>
  );
}

SVGR with Vite

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  plugins: [
    react(),
    svgr({
      svgrOptions: {
        icon: true,
        typescript: true,
        svgo: true,
      },
    }),
  ],
});

// Usage with named import:
import { ReactComponent as Logo } from './logo.svg';
// or default import depending on config:
import Logo from './logo.svg?react';

SVGR supports extensive configuration through .svgrrc.json or the svgr key in package.json. Common options include setting the default export type, enabling TypeScript, controlling whether to include the title element for accessibility, and customizing the component template.

.svgrrc.json configuration

{
  "icon": true,
  "typescript": true,
  "svgo": true,
  "titleProp": true,
  "replaceAttrValues": {
    "#000": "currentColor",
    "#000000": "currentColor"
  },
  "svgoConfig": {
    "plugins": [
      { "name": "removeViewBox", "active": false },
      { "name": "removeDimensions", "active": true },
      { "name": "removeTitle", "active": false }
    ]
  },
  "template": null
}

Inline SVG vs External SVG Files

There are two main approaches to using SVG in React, each with different trade-offs:

Inline SVG (as JSX components)

  • Pros: Full CSS/JS control, dynamic props, tree-shakable, no extra HTTP requests
  • Cons: Increases JavaScript bundle size, cannot be cached independently, SSR markup is larger
  • Best for: Icons, logos, small illustrations (under 5KB each)

External SVG files (via img tag or CSS)

  • Pros: Separate caching, smaller JS bundle, browser-native rendering
  • Cons: No dynamic styling, extra HTTP request, no JS interaction
  • Best for: Large illustrations, complex diagrams, decorative backgrounds

A hybrid approach works well: use inline SVG components for interactive icons and UI elements, and external SVG files for large decorative graphics. The threshold is roughly 5KB: below that, inline; above that, external.

// Inline SVG as component (best for icons)
import SearchIcon from '@/icons/SearchIcon';

function SearchBar() {
  return (
    <div className="search-bar">
      <SearchIcon size={20} color="var(--text-muted)" />
      <input type="text" placeholder="Search..." />
    </div>
  );
}

// External SVG via img tag (best for large illustrations)
function HeroSection() {
  return (
    <section>
      <h1>Welcome</h1>
      <img
        src="/illustrations/hero-graphic.svg"
        alt="Developer tools illustration"
        width={600}
        height={400}
        loading="lazy"
      />
    </section>
  );
}

Accessibility Best Practices for SVG in React

Making SVG components accessible requires attention to a few key details. Decorative SVGs should be hidden from screen readers, while meaningful SVGs need proper labels:

// Meaningful SVG - conveys information
const WarningIcon = ({ message }: { message: string }) => (
  <svg
    role="img"
    aria-label={message}
    viewBox="0 0 24 24"
    width={24}
    height={24}
  >
    <title>{message}</title>
    <path d="M12 2L1 21h22L12 2zm0 4l7.5 13h-15L12 6z" fill="currentColor" />
    <path d="M11 10h2v5h-2zm0 6h2v2h-2z" fill="currentColor" />
  </svg>
);

// Decorative SVG - hidden from assistive technology
const DividerIcon = () => (
  <svg
    aria-hidden="true"
    focusable="false"
    viewBox="0 0 100 2"
    width={100}
    height={2}
  >
    <line x1="0" y1="1" x2="100" y2="1" stroke="currentColor" />
  </svg>
);

Key accessibility rules for SVG in React:

  • Add role="img" and aria-label for meaningful SVGs that convey information
  • Add aria-hidden="true" for decorative SVGs that do not convey meaning
  • Include a <title> element inside the SVG as a fallback description
  • Use focusable="false" to prevent keyboard focus on decorative SVGs in older browsers
  • Ensure sufficient color contrast for SVG icons (WCAG 2.1 requires 3:1 ratio for UI components)

Performance Optimization Tips

SVG components can impact performance if not handled carefully. Here are strategies to keep your React app fast:

Optimize SVG before converting: Use SVGO (SVG Optimizer) to remove unnecessary metadata, comments, editor data, empty groups, and default values. This can reduce SVG size by 30-70%.

Use React.memo for icon components: Since icons rarely change based on new props, wrapping them in React.memo() prevents unnecessary re-renders when parent components update.

Lazy-load large SVG sets: If your app has hundreds of icons, use React.lazy() with dynamic imports to code-split icon bundles.

Use SVG sprites for repeated icons: For icons used across many pages, an SVG sprite sheet with <use> references can be more efficient than individual components.

Prefer currentColor: Using fill="currentColor" lets the SVG inherit text color from its parent CSS, eliminating the need for extra style props and enabling theme switching without re-renders.

// Memoized icon component - prevents unnecessary re-renders
import React from 'react';

interface IconProps extends React.SVGProps<SVGSVGElement> {
  size?: number;
}

const StarIcon = React.memo<IconProps>(({ size = 24, ...props }) => (
  <svg
    width={size}
    height={size}
    viewBox="0 0 24 24"
    fill="currentColor"
    {...props}
  >
    <path d="M12 2l3.09 6.26L22 9.27l-5 4.87
             1.18 6.88L12 17.77l-6.18 3.25L7 14.14
             2 9.27l6.91-1.01L12 2z" />
  </svg>
));
StarIcon.displayName = 'StarIcon';

// Lazy-loaded icon set for code splitting
const ChartIcons = React.lazy(() => import('./ChartIconSet'));

function Dashboard() {
  return (
    <React.Suspense fallback={<div style={{ width: 24, height: 24 }} />}>
      <ChartIcons.BarChart size={32} />
    </React.Suspense>
  );
}

// SVG sprite with <use> for repeated icons
function SpriteIcon({ id, size = 24 }: { id: string; size?: number }) {
  return (
    <svg width={size} height={size} aria-hidden="true">
      <use href={`/icons/sprite.svg#${id}`} />
    </svg>
  );
}

TypeScript Support for SVG Components

When using TypeScript, proper typing ensures your SVG components integrate seamlessly with your codebase. Here is how to type SVG components correctly:

// types/svg.d.ts - Enable SVG imports as React components
declare module '*.svg' {
  import React from 'react';
  const SVGComponent: React.FC<React.SVGProps<SVGSVGElement>>;
  export default SVGComponent;
}

// For Vite with vite-plugin-svgr:
declare module '*.svg?react' {
  import React from 'react';
  const SVGComponent: React.FC<React.SVGProps<SVGSVGElement>>;
  export default SVGComponent;
}

// Reusable icon component type
interface IconComponentProps extends React.SVGProps<SVGSVGElement> {
  size?: number;
  color?: string;
  title?: string;
}

// Icon factory function with proper types
function createIcon(
  path: string,
  displayName: string
): React.FC<IconComponentProps> {
  const Icon: React.FC<IconComponentProps> = ({
    size = 24,
    color = 'currentColor',
    title,
    ...props
  }) => (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      stroke={color}
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
      role={title ? 'img' : undefined}
      aria-label={title}
      aria-hidden={!title}
      {...props}
    >
      {title && <title>{title}</title>}
      <path d={path} />
    </svg>
  );
  Icon.displayName = displayName;
  return React.memo(Icon);
}

With SVGR and TypeScript, you can also generate .d.ts declaration files for SVG imports. Add this to your project type declarations:

SVG in Next.js Projects

Next.js requires a specific setup for SVG-as-component imports. The recommended approach uses @svgr/webpack:

// next.config.ts (Next.js 13+ with App Router)
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  webpack(config) {
    // Find the existing rule that handles SVG imports
    const fileLoaderRule = config.module.rules.find(
      (rule: { test?: RegExp }) => rule.test?.test?.('.svg')
    );

    config.module.rules.push(
      // Reapply the existing rule, but only for svg imports
      // ending in ?url (e.g. import iconUrl from './icon.svg?url')
      {
        ...fileLoaderRule,
        test: /\.svg$/i,
        resourceQuery: /url/,
      },
      // Convert all other *.svg imports to React components
      {
        test: /\.svg$/i,
        issuer: fileLoaderRule.issuer,
        resourceQuery: {
          not: [...(fileLoaderRule.resourceQuery?.not || []), /url/],
        },
        use: [
          {
            loader: '@svgr/webpack',
            options: {
              typescript: true,
              svgo: true,
              titleProp: true,
            },
          },
        ],
      }
    );

    // Modify the file loader rule to ignore *.svg
    fileLoaderRule.exclude = /\.svg$/i;

    return config;
  },
};

export default nextConfig;

After configuration, you can import SVGs as React components directly in your Next.js pages and components. The webpack loader handles the conversion at build time, so there is no runtime overhead.

Frequently Asked Questions

How do I convert SVG to a React component?

Convert SVG to a React component by transforming HTML attributes to JSX equivalents (class to className, hyphenated attributes to camelCase), wrapping the SVG markup in a function component, and exporting it. Use SVGR for automated conversion, or our free online SVG to JSX converter tool for quick one-off transformations.

What is the difference between SVG to JSX and SVG to React?

SVG to JSX converts the attribute syntax (class to className, fill-rule to fillRule, etc.) so the markup is valid JSX. SVG to React goes further by wrapping the JSX in a proper React component with props support, TypeScript types, and export statements. Most tools do both steps together.

Should I inline SVG or use img tags in React?

Inline SVG as React components for icons and small graphics (under 5KB) that need styling control or interactivity. Use img tags for large decorative SVGs, complex illustrations, or SVGs that benefit from browser caching. A hybrid approach often works best.

How do I make SVG components accessible?

For meaningful SVGs, add role="img" and aria-label with a descriptive label. For decorative SVGs, add aria-hidden="true" and focusable="false". Always include a title element inside the SVG as a fallback.

Can I use SVG with React Native?

Yes, but React Native does not support SVG natively. Use the react-native-svg library which provides SVG components (Svg, Path, Circle, etc.) that map to native platform primitives. SVGR also has a React Native mode that generates compatible components.

Converting SVG to React components gives you the best of both worlds: resolution-independent graphics with full React interactivity and theming support. For quick conversions, use our online tool. For project-wide SVG handling, set up SVGR in your build pipeline. Always optimize your SVGs with SVGO first, and follow accessibility best practices to ensure your icons work for all users.

Convert SVG to JSX with our free online tool.

Related Developer Tools and Guides

𝕏 Twitterin LinkedIn
Was this helpful?

Stay Updated

Get weekly dev tips and new tool announcements.

No spam. Unsubscribe anytime.

Try These Related Tools

SVGSVG to JSX/ReactJSXHTML to JSX

Related Articles

SVG to JSX: Convert SVG to React Components (Free Online Tool)

Free SVG to JSX converter. Transform raw SVG into optimized React/JSX components instantly. Covers SVGO optimization, className conversion, accessibility, and TypeScript props.

SVG viewBox Explained: Width, Height, Scaling & Responsive SVGs

Demystify the SVG viewBox attribute. Learn how min-x, min-y, width, and height control the coordinate system, and how to make SVGs fully responsive.

HTML to JSX: Everything You Need for React Migration

A comprehensive guide to converting HTML to JSX for React. Covers className, style objects, self-closing tags, event handlers, and common gotchas.