SVG to React: cleanup and JSX patterns

Published: 2026-09-05

Why design-tool SVG needs SVGO cleanup, how HTML attributes become camelCase JSX props, and when to export a React component versus optimized markup.

Exporting an icon from Figma, Illustrator, or a stock pack rarely produces React-ready markup. You get editor metadata, long decimal path data, class instead of className, and kebab-case attributes that JSX rejects. Turning that into a clean component is mostly two steps: optimize the SVG, then serialize it with React’s attribute rules.

What “cleanup” usually removes

Design tools and older exporters often leave baggage that browsers ignore but that inflates bundles and confuses diffs:

Typical cruft Why remove it
Editor comments / generator stamps Noise in git; no runtime value
Unused id, defs, or hidden layers Dead weight after flattening
Excess path precision 1.000000 vs 1 — same shape, fewer bytes
Default fill/stroke when CSS will own color Easier theming with currentColor

SVGO (and similar optimizers) apply those transforms as a pipeline of plugins. Aggressive presets shrink more but can drop titles, descriptions, or IDs you still need for accessibility or CSS hooks—choose a milder profile when those matter. For minify-only workflows without a React wrapper, see the SVG Minifier.

HTML SVG attributes vs JSX

SVG in HTML uses kebab-case attribute names and HTML-ish spellings. React’s JSX layer expects camelCase DOM property names (same idea as converting identifiers between case styles):

In SVG / HTML In JSX
class className
stroke-width strokeWidth
fill-rule fillRule
clip-path clipPath
xlink:href xlinkHref (legacy)
xml:space xmlSpace

Numeric-looking values often become strings in markup (width="24"); JSX may keep them as strings or numbers depending on your serializer. Self-closing tags (<path … />) are normal in JSX even when the original SVG used paired tags.

Pasting raw SVG into a .jsx file without renaming attributes is a common compile error. Converters that walk the DOM and rewrite names avoid that busywork.

Component patterns that stay maintainable

A practical React icon component:

  1. Named export (export function IconName) so tree-shaking and imports stay clear.
  2. Spread …props on the root <svg> so callers can pass className, aria-*, width/height, or style without editing the file.
  3. TypeScript: type props as SVGProps<SVGSVGElement> so IDE autocomplete matches native SVG attributes.
  4. Prefer currentColor (or omit fill) so the icon inherits text color from CSS instead of hard-coded hex from the design tool.

Example shape (illustrative):

import type { SVGProps } from 'react';

export function CheckIcon(props: SVGProps<SVGSVGElement>) {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path d="…" stroke="currentColor" strokeWidth={2} />
    </svg>
  );
}

Keep one icon per file (or a small barrel) unless you deliberately ship a sprite sheet. Inline components beat data-URL blobs when you need theming and accessibility props.

JSX, TSX, or optimized SVG string?

Output Best when
JSX component App uses JavaScript; no type imports needed
TSX component TypeScript React app; you want SVGProps on the root
Optimized SVG You still need a .svg asset, CSS mask, or a non-React consumer

Optimization first, then format choice, keeps path data and attributes consistent across all three.

Why run this locally

SVG exports sometimes include client logos, unreleased UI, or path data that encodes product screens. Uploading those to a random “SVG → React” site is an unnecessary leak. A browser tool that runs SVGO in a Web Worker and converts with DOMParser on-device keeps the markup in your tab—see Why “local only” matters for developer tools.

SVG is XML under the hood; for general well-formedness and pretty-print of arbitrary XML (not React-specific), see Validating and formatting XML in the browser.

Try it on LocalTools

Paste or drop an .svg into SVG to JSX: SVGO cleans the markup in a worker, then you choose JSX, TSX (with SVGProps), or optimized SVG and copy the result—nothing is uploaded.

Related reading

All learn articles