SVG to JSX Converter: React SVG Optimization Done Right
Copying an SVG from Figma or an icon library into a React component sounds trivial until the build fails with "Unknown prop stroke-width on <path> tag." SVG attributes use kebab-case in HTML but camelCase in JSX. Class becomes className. XML declarations break parsers. The SVG to JSX online converter handles every transformation automatically, outputting a typed, composable React component in one click.
Why Raw SVG Breaks in JSX
The JSX syntax is a JavaScript expression that compiles to React.createElement() calls. It follows JavaScript naming rules, which means:
- Hyphenated attributes are invalid identifiers.
stroke-widthis subtraction in JS. JSX requiresstrokeWidth. classis a reserved keyword. JSX usesclassName.foris a reserved keyword. JSX useshtmlFor.- XML declarations (
<?xml … ?>) are not JSX. They must be stripped. - HTML comments (
<!-- -->) are not valid JSX. They must be removed or converted to{/* */}. - Inline
styleattributes must be objects.style="fill: red"becomesstyle={{ fill: 'red' }}.
The converter resolves all of these transformations in a single pass using a deterministic attribute map of 30+ SVG-specific properties.
The Attribute Transformation Map
The core of the conversion is a static lookup table mapping every hyphenated SVG attribute to its camelCase JSX equivalent:
stroke-width → strokeWidth
stroke-linecap → strokeLinecap
stroke-linejoin → strokeLinejoin
stroke-dasharray → strokeDasharray
stroke-dashoffset → strokeDashoffset
stroke-miterlimit → strokeMiterlimit
fill-rule → fillRule
fill-opacity → fillOpacity
clip-path → clipPath
clip-rule → clipRule
color-interpolation → colorInterpolation
flood-color → floodColor
flood-opacity → floodOpacity
lighting-color → lightingColor
stop-color → stopColor
stop-opacity → stopOpacity
font-family → fontFamily
font-size → fontSize
font-style → fontStyle
font-weight → fontWeight
text-anchor → textAnchor
dominant-baseline → dominantBaseline
glyph-orientation-vertical → glyphOrientationVertical
glyph-orientation-horizontal → glyphOrientationHorizontal
marker-start → markerStart
marker-mid → markerMid
marker-end → markerEnd
vector-effect → vectorEffect
shape-rendering → shapeRendering
image-rendering → imageRendering
color-rendering → colorRendering
xmlns:xlink → (removed — not needed in React)
xlink:href → href
Beyond attribute renaming, the converter also removes XML namespace declarations and Inkscape/Illustrator editor metadata (<sodipodi:*>, <inkscape:*>, <metadata>), which are meaningless at runtime and bloat the bundle.
How to Use the SVG to JSX Converter
Step 1 — Paste raw SVG
Copy the complete SVG markup from Figma (right-click → Copy as SVG), from an icon library source file, or from a .svg file. Paste it into the left panel.
Step 2 — Read the generated component The right panel shows a complete TypeScript functional component:
import { SVGProps } from 'react';
export function IconArrow(props: SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeWidth={1.5}
stroke="currentColor"
{...props}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"
/>
</svg>
);
}
Step 3 — Copy and integrate
The component is ready to drop into your components/icons/ directory. Rename the function from Root to the appropriate icon name.
The SVGProps Spread Pattern
The generated component spreads SVGProps<SVGSVGElement> onto the root <svg>. This is a deliberate design decision that makes the component maximally composable:
// Override size
<IconArrow width={32} height={32} />
// Change colour
<IconArrow stroke="#ff4500" />
// Add a class
<IconArrow className="animate-spin" />
// Fully control fill
<IconArrow fill="currentColor" stroke="none" />
All standard SVG attributes are available without any prop drilling. This pattern follows the compound component principle: the component provides sensible defaults but yields control to the consumer.
React SVG Optimization: Bundle Size Considerations
Raw SVGs imported with a bundler (e.g., via SVGR) add to your JavaScript bundle. Every node in the SVG tree becomes a JSX element. For icon-heavy UIs, this compounds:
- A 24-pixel icon with 3 paths adds ~200 bytes gzipped to the bundle.
- 100 such icons add ~20 KB — noticeable on mobile.
Optimisation strategies:
1. Run SVGO before converting. SVGO removes redundant nodes, simplifies paths, and trims precision. A typical SVGO pass reduces SVG file size by 40–60%. Apply it to the raw SVG before pasting into the converter for maximum benefit.
2. Use sprite sheets for repeated icons. Rather than rendering each icon as an inline component, define a <symbol> sprite sheet and reference icons with <use href="#icon-name" />. This reduces DOM node count significantly.
3. Lazy-load icon-heavy panels. If a settings panel uses 20 icons but appears infrequently, wrap it in React.lazy() and Suspense so the icon bundle is only fetched when needed.
4. Prefer currentColor for themeable icons. Setting stroke="currentColor" and fill="currentColor" means the icon inherits the CSS color property, making theming trivial with a single CSS variable.
Comparison: Manual Conversion vs. Automated Tools
| Method | Time | Handles all attributes | TypeScript output | Removes editor noise |
|---|---|---|---|---|
| Manual rewrite | 5–15 min per icon | Depends on engineer | Manual | Manual |
| SVGR CLI | ~10 sec (+ config) | ✓ | ✓ (with plugin) | Partial |
| This online converter | Instant | ✓ (30+ attrs) | ✓ | ✓ |
| Paste JSON as Code IDE plugin | N/A | N/A | N/A | N/A |
The online developer utility is the fastest path from raw SVG to a production-ready React component. SVGR is better for automated pipelines (CI/CD, build-time icon generation), but for one-off conversions or when you cannot add build tooling, this tool is the right choice.
Common Issues and Solutions
Empty output — The input is not valid SVG. Ensure the markup starts with <svg (not a <div> wrapper from Figma).
viewBox missing — Some SVG exports omit viewBox and only specify width/height. The component will still render, but it will not scale proportionally. Add viewBox="0 0 W H" manually.
id conflicts — If you render multiple copies of the same icon on a page and the SVG uses internal id references (e.g., for <clipPath> or <linearGradient>), duplicate IDs will cause rendering bugs. Append a unique suffix: id="gradient-${uid}".
Inline styles not converted — The converter removes inline style string attributes because parsing CSS-in-a-string requires a full CSS parser. Move styles to explicit SVG presentation attributes before converting, or handle them post-conversion.