SVGFlow
Open editor

SVG to JSX

Convert SVG to a React component. camelCase attributes, a style object instead of a style string, and a props spread on the root so callers can override anything.

Runs entirely in your browser — nothing is uploaded, no account needed.

Previewno file
Drop an SVG to convert
Or paste markup below · max 2 MB
Component
Open an SVG to see the component.
Component name

How to convert SVG to JSX

Drop an SVG file — or paste the <svg> element straight out of a page or a design-tool export — and the markup is parsed by your browser's own DOMParser and rewritten as a React function component. Nothing is uploaded; the conversion is a tree walk on your machine. Hyphenated attributes become their camelCase DOM names, string style attributes become style objects, and the component name is derived from the file name — arrow-left.svg becomes ArrowLeft — unless you type one. The props spread sits last on the root element, so a caller's className, width or onClick wins over the file's defaults.

The output is deliberately plain: one exported function, no imports, no wrapper. It drops into a .jsx file as-is under the modern JSX transform, and the copy button and download name track the component name and the TypeScript toggle.

Why SVG markup cannot be pasted into JSX directly

JSX looks like HTML but compiles to property assignments, and SVG's attribute names are full of characters that are illegal in that position. stroke-width must become strokeWidth, fill-rule becomes fillRule, stop-color becomes stopColor — React warns about every one it finds in the original spelling. A handful are special cases rather than mechanical renames: class is a reserved word and becomes className, tabindex becomes tabIndex, and the namespaced xlink:href becomes xlinkHref (with the xmlns:xlink declaration removed outright, since JSX has no use for it). Two families are deliberately left alone: data-* and aria-* attributes are valid in JSX exactly as written, and renaming them would break both styling hooks and screen readers.

The style attribute is the other structural change. HTML takes a CSS string; React takes an object. A style="fill:none;stroke:red" from an editor export is rebuilt as style={{ fill: 'none', stroke: 'red' }}, with each property name camelCased by the same rule. Doing this by hand across a set of icons is exactly the kind of tedium that produces the one typo you hunt for an hour.

Using the component in a real codebase

Because the spread is on the root <svg> and placed after the file's own attributes, the component needs no prop plumbing at all: <ArrowLeft width={16} height={16} /> overrides the exported size, className attaches your styles, and onClick just works. The one thing worth doing before conversion is colour: if the fill is hard-coded from the export, the icon will ignore your theme. Swap fills to currentColor in the Color Replacer first and the rendered colour follows the surrounding text — hover states, dark mode and disabled states come free through CSS color. For icons that are purely decorative, pass aria-hidden="true" at the call site; for meaningful ones, a role="img" and aria-label — the accessible icons guide covers which is which.

The TypeScript option

With TypeScript on, the signature becomes (props: React.SVGProps<SVGSVGElement>) and the download switches to .tsx. That type is the same one React uses for a literal <svg> element, so every SVG attribute, every event handler and ref-free usage type-checks without you writing an interface. It also acts as a lint: attributes that some editors write into their exports but that are not part of React's SVG typings will be flagged by the compiler — the Optimizer's editor-attribute pass strips them at the source, which is the better fix.

Common problems

  • Two icons swap fills when mounted together. Both define a gradient or clip path with the same id, and ids are document-global — the second definition wins for both. Namespace ids per instance with useId(); the React guide has the exact pattern.
  • The component ignores className or sizing. The spread was toggled off, or got moved above the default attributes in later editing. It has to be present and last — JSX resolves duplicate props left to right.
  • The colour is stuck. The fill is still hard-coded from the export. Convert it to currentColor in the Color Replacer before converting, and the component follows its container's text colour.
  • Comments and editor metadata are gone. The walk emits elements and text; XML comments are not carried into JSX (which has no syntax for them in that position). Nothing that renders is affected.

When a component is the wrong shape

A component per icon is the right call for the handful of icons an app shell renders on every screen. It is the wrong call for a long tail of two hundred occasional icons — every one becomes bundle bytes parsed on load whether it is used or not. For that case, an SVG sprite keeps one cached document and references icons by fragment; for purely decorative backgrounds, a CSS data URI avoids JavaScript entirely. And run anything you do convert through the Optimizer first — everything it removes is weight the component would otherwise carry into your bundle forever. Projects converting icons continuously are better served by a build-time transform; this tool is for the gradual case — paste, name, copy, next — with no build configuration at all.

Questions

Is this SVG to JSX converter free?

Yes. Converting SVG to React components here is free, with no account, no watermark and no conversion limit. The site is funded by advertising.

Is my SVG uploaded to a server?

No. The markup is parsed and rewritten by your own browser — there is no upload endpoint, and the converted component never exists anywhere but your machine until you paste it somewhere.

Why do SVG attributes need to be camelCase in React?

JSX compiles attributes to JavaScript property names, and hyphens are illegal there. stroke-width must be strokeWidth, fill-opacity must be fillOpacity, and class — a reserved word — becomes className. React warns on every attribute left in its original spelling; the converter renames all of them in one pass.

What happens to data-* and aria-* attributes?

They are kept exactly as written. JSX accepts both families in their hyphenated form, and camelCasing them would silently break test selectors and screen-reader labels.

How is the style attribute handled?

A style string from the source file is converted to a React style object — each declaration becomes a camelCased key with a string value. Style objects are what React requires; a string style attribute is a runtime error.

What does the "spread props" option do?

It adds {...props} as the last thing on the root <svg>, so whatever the caller passes — className, width, onClick, aria-label — overrides the file’s baked-in values. Leaving it on is recommended; without it the component accepts props and ignores them.

Can it output TypeScript?

Yes. Tick TypeScript and the component is typed as React.SVGProps<SVGSVGElement> and downloads as a .tsx file. That is the same prop type as a native <svg> element, so all attributes and handlers type-check.

Where does the component name come from?

From the file name, PascalCased — arrow-left.svg becomes ArrowLeft. Type your own name to override it; it is restricted to letters and digits because it has to be a valid JavaScript identifier.

Do I need to import React in the output file?

Not with the modern JSX transform (React 17+, and any current bundler default). The output is a plain exported function with no import line; on an older classic-transform setup, add the React import yourself.

Why do two converted icons interfere with each other on one page?

Duplicated ids. Gradients, clip paths and masks are referenced by id, and ids are global to the HTML document — two components defining #gradient both resolve to whichever mounted last. Suffix the ids per instance, for example with React's useId hook — the SVG to React guide shows the pattern.

Should I optimize the SVG before converting it?

Yes. Editor exports carry metadata, default-value attributes and generous path precision, and all of it becomes permanent bundle weight once it is a component. Run the file through the Optimizer first, then convert.

Can I convert the same icon for Vue, Svelte or React Native?

Yes — Vue, Svelte and React Native each have their own converter, emitting what is idiomatic there rather than translated JSX. The same source file works in all of them.

Notes

  • Hyphenated attributes become camelCase — except data-* and aria-*, which stay as they are.
  • If two icons on the same page define a gradient with the same id, one will render with the other's fill. Namespace ids per instance with useId(). There is a guide on this.
  • The spread goes last so a caller-supplied className, width or onClick wins over the defaults.

Related tools