Skip to content

SVGEditor

Free online SVG editor for live preview, share, React & PNG

Tool SVG Animation Editor Guide Privacy Terms
Open Source
Home / Convert SVG to React (JSX)

Guide

How to Convert SVG to a React Component with JSX

Not every SVG belongs in your JS bundle. This guide explains currentColor theming, React Native, TypeScript, SVGR vs paste-JSX, Next.js, and when not to inline an icon. It is based on SVGEditor’s actual exporter—not a “rename attributes and hope” checklist.

Published August 6, 2026 · Updated August 12, 2026

Roman Riaboshtan, creator of SVGEditor

By Roman Riaboshtan

Creator of SVGEditor · full-stack developer (Python & React). Built the in-browser React / React Native exporter — attribute mapping, props spread, and the limits versus SVGR — and wrote this guide from that pipeline.

Skip the manual rewrite: paste your SVG into the editor, then use the React or React Native export tab.

Open SVG → React converter

On this page

  1. Why convert SVG to React
  2. Worked example
  3. Manual SVG → JSX
  4. Convert online
  5. React Native
  6. SVGR vs paste-JSX
  7. What the exporter does
  8. Sanitize untrusted SVG
  9. Design-system patterns
  10. Bundle cost
  11. Accessibility
  12. Next.js / RSC
  13. Common mistakes
  14. Production checklist
  15. FAQ
SVGEditor with Source SVG on the left and the React export tab showing a generated Icon component on the right
Real UI: paste SVG on the left, open the React tab, copy the component.

Why convert SVG to a React component?

Dropping SVG into an <img> works for static art, but components win when you need to change color, size, or accessibility from props. Inline JSX (or react-native-svg) lets you pass className, width, fill, and ARIA attributes like any other React element.

Design tools often export verbose SVG. Clean it up once, wrap it as an Icon component, and keep your UI kit consistent across web and mobile.

That said: not every SVG belongs in your JS bundle. Large illustrations you never recolor should stay as <img> or a static asset. Reserve React components for UI chrome — buttons, nav, and status icons — where theming and props matter.

Worked example: icon for a dark UI

A common handoff: Figma exports an icon with hard-coded #000 fills. In a dark app that icon disappears — or fights the theme. Here is the workflow we use with SVGEditor.

Before: black #000 icon nearly invisible on a dark SVGEditor-style bar. After: the same icon with currentColor in cyan, clearly visible.
Before: hard-coded black fills vanish on a dark UI. After: currentColor follows the theme.

Before — static SVG (fine as <img>, weak as UI chrome):

<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  <path fill="#000000" d="M12 2L2 7l10 5 10-5-10-5z"/>
  <path fill="#000000" d="M2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>

After — paste into SVGEditor, keep the React tab open, then set strokes/fills to currentColor (or edit the exported JSX once):

export default function LayersIcon(props) {
  return (
    <svg viewBox="0 0 24 24" width={24} height={24} fill="none" {...props}>
      <path
        d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"
        stroke="currentColor"
        strokeWidth={1.5}
        strokeLinejoin="round"
      />
    </svg>
  );
}

// Nav / button — color follows theme
<LayersIcon className="text-sky-300" aria-hidden="true" />

On the React Native tab, the same markup becomes <Svg> / <Path> with numeric props — useful when design shares one SVG and web + mobile both need a component.

Manual path: SVG → React JSX

For a tiny icon you can convert by hand in a minute:

  1. Copy the SVG markup (or download the .svg file and open it as text).
  2. Rename attributes to JSX: class → className, stroke-width → strokeWidth, fill-rule → fillRule, and so on.
  3. Wrap the root <svg> in a function component and spread {...props} so callers can override size and style.
  4. Prefer fill="currentColor" or stroke="currentColor" when the icon should inherit text color.
  5. If the SVG came from an untrusted upload, sanitize first — see Sanitize untrusted SVG.
export default function Icon(props) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={24}
      height={24}
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        d="M12 2L2 7l10 5 10-5-10-5z"
        stroke="currentColor"
        strokeWidth={1.5}
      />
    </svg>
  );
}

Keep viewBox — that is what makes the icon scale cleanly when you change width / height. Prefer numeric props (width={24}) so the same mental model works on web and React Native.

How to convert SVG to React online

Use SVGEditor’s SVG to React converter when you want JSX (or React Native) without wiring up SVGR. You do not need an account, and nothing is uploaded to a server—typically, you can go from paste to a file in your repo in a few minutes.

  1. Paste or upload your SVG

    Open the converter. Paste markup into Source or use Upload for a .svg file. Check the live preview so fills, viewBox, and unusual markup look right before you export — conversion stays in your browser.

  2. Copy the React JSX component

    Open the React tab (already selected on the tool page). Copy the generated Icon component: kebab-case attributes become JSX (stroke-width → strokeWidth), and {...props} sits on the root <svg> so callers can pass className, width, and ARIA attributes.

  3. Or export React Native instead

    Need mobile? Switch to the React Native tab. SVGEditor maps tags to react-native-svg (Svg, Path, Circle, …), adds the import, and uses numeric props like width={24}. Install react-native-svg in the app, then paste the snippet.

  4. Drop it into your UI kit

    Save as .jsx or .tsx (type props as React.SVGProps<SVGSVGElement> on web). Prefer currentColor for chrome icons so themes work. Keep viewBox; override size via props. Decorative icons get aria-hidden="true".

Prefer a bundler pipeline for dozens of repo .svg files? Use SVGR — see the comparison below. For one-offs, drafts, and shareable previews, the paste-JSX path is enough.

React Native notes

React Native does not render raw HTML SVG markup directly. Install react-native-svg and use the generated component:

import Svg, { Path } from "react-native-svg";

export default function Icon(props) {
  return (
    <Svg viewBox="0 0 24 24" width={24} height={24} {...props}>
      <Path d="M12 2L2 7l10 5 10-5-10-5z" stroke="currentColor" strokeWidth={1.5} />
    </Svg>
  );
}

Numeric props like width and strokeWidth should be numbers in RN, not quoted strings. SVGEditor’s React Native export follows that convention.

For TypeScript on RN, type against react-native-svg’s props (for example React.ComponentProps<typeof Svg>) instead of React.SVGProps<SVGSVGElement> — that DOM type is web-only.

Color theming differs too: web often uses CSS currentColor + className; RN usually passes color / stroke / fill as props from your theme object.

SVGR vs paste-JSX (and Next.js)

Teams usually choose between two pipelines. Neither is wrong—they solve different problems.

When you… Prefer SVGR Prefer SVGEditor (paste JSX)
Icon volume Steady stream of .svg files in the repo One-off icons, drafts, quick handoffs
Build setup OK adding a Vite / webpack / Next plugin No bundler change — just a .jsx / .tsx file
Preview / share In the app after import Live preview + share/embed link in the browser
React Native Separate RN pipeline / config Same paste flow → React Native tab

In Next.js, do not pass interactive icons through next/image. That helper is for raster (and some static assets); it will not give you prop-driven fill / stroke the way an inline component does. Prefer either SVGR or a pasted component under components/icons/.

// components/icons/Mark.tsx — pasted from SVGEditor React export
export default function Mark(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" width={24} height={24} fill="none" {...props}>
      <path d="M12 2L2 7l10 5 10-5-10-5z" stroke="currentColor" strokeWidth={1.5} />
    </svg>
  );
}

// usage — color follows CSS / theme
<Mark className="text-sky-400" aria-hidden="true" />

For dark mode, hard-coded fills fight the theme. Export (or edit) strokes/fills to currentColor, then set color on the component or a parent. That is the usual reason people convert SVG to React instead of shipping a static .svg URL.

Exception: multicolor brand logos. Do not force every path to currentColor or you will flatten the brand. Keep fixed brand fills, or expose named props (primary / accent) for the few paths that should theme.

What SVGEditor’s React export does (and does not)

Understanding this boundary sets realistic expectations and explains why both paste-JSX and SVGR still exist.

  • Does: walk the SVG tree into a function component; map kebab-case attrs to JSX (stroke-width → strokeWidth); spread {...props} on the root so callers own className, size, and ARIA; offer a parallel react-native-svg tree with numeric props.
  • Does not: run SVGO-style path rewriting, dedupe gradients across files, or invent currentColor for you. Preview first; fix fills in Source (or in the copied JSX) when the icon must theme.
  • Why {...props} on the root: so one icon file stays flexible — buttons pass className, tests pass data-testid, a11y passes aria-label — without regenerating the component.

Internal ids (gradients, clipPaths) can collide if you mount the same raw markup twice on one page. Prefer unique ids per icon file, or strip unused defs after export when you only need paths.

Leaving xmlns="http://www.w3.org/2000/svg" on a web React <svg> is harmless (browsers already treat it as SVG in HTML). On React Native it is unused — the react-native-svg export omits it. Editor junk (data-name, empty <g>, unused clipPaths) is worth stripping before you commit: smaller SVG means smaller JSX.

Sanitize untrusted SVG before you convert

JSX export does not make hostile markup safe. If the SVG came from a user upload, a paste from the internet, or a share link, treat it as untrusted before it becomes a component in your app.

  • Strip script, event handlers, foreignObject, and hostile SMIL — the same surfaces that cause SVG XSS when inlined.
  • SVGEditor sanitizes on paste/upload before preview and before React / React Native export, so you do not copy a payload that still carries active content.
  • For a production upload pipeline, keep a server-side (or Worker) sanitizer too — see Sanitize SVG for XSS for DOMPurify config, CSP, and the checklist.

Trusted design-system files from your repo are a different lane. Untrusted uploads are not. Mixing them is how “icon upload” features become XSS bugs.

Design-system patterns (TypeScript, refs, tree-shaking)

Once you paste JSX once or twice, the next step is a small icon kit that scales. Patterns that hold up in production:

Type props and forward refs when parents need the DOM node

import { forwardRef } from "react";

const SearchIcon = forwardRef<SVGSVGElement, React.SVGProps<SVGSVGElement>>(
  function SearchIcon(props, ref) {
    return (
      <svg
        ref={ref}
        viewBox="0 0 24 24"
        width={24}
        height={24}
        fill="none"
        aria-hidden="true"
        {...props}
      >
        <path
          d="M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
          stroke="currentColor"
          strokeWidth={1.5}
        />
      </svg>
    );
  }
);

export default SearchIcon;

Use forwardRef when a tooltip, focus manager, or animation library needs the underlying <svg>. For most decorative icons, a plain function component is enough.

Named files beat mega barrels

Prefer components/icons/SearchIcon.tsx over one icons.tsx that re-exports everything. Bundlers tree-shake unused files more reliably than giant barrels — especially under Next.js App Router.

Default size, keep viewBox, let props win

Ship a sensible default (width={24} / height={24}), always keep viewBox, and spread {...props} last so callers can override size, className, and a11y attributes without editing the icon file.

Stroke icons vs fill icons

Many Figma exports are stroke-based. Setting fill="currentColor" on a stroke icon does nothing useful — and leaving fill="#000" on a fill icon breaks dark mode. Match the paint mode: stroke icons → stroke="currentColor" + fill="none"; fill icons → fill="currentColor".

Bundle cost: component vs <img> vs sprite

A React icon adds JavaScript to your bundle. That is fine for a UI kit of dozens of small marks, but it is the wrong default for a 200 KB illustration you never recolor.

Approach Best when… Watch out for…
React / RN component Theme color, props, a11y, shared web+mobile JS weight if you paste huge illustrations
<img src=".svg"> Static art, cacheable asset, no recolor No currentColor; harder a11y hooks
SVG sprite / symbol Many static icons, one HTTP fetch Theming and tree-shaking are clumsier than components
PNG handoff Email, decks, CMS uploads Fixed pixels — see the SVG → PNG guide

Rule we use in SVGEditor itself: chrome icons → components with currentColor; marketing bitmaps → PNG when the destination cannot take SVG. See Convert SVG to PNG for the raster handoff.

Accessibility and id hygiene

Decorative icons in buttons that already have text should set aria-hidden="true" (and usually focusable="false" on the SVG) so screen readers do not announce path soup. Standalone icons need an accessible name:

export default function SearchIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" width={24} height={24} aria-hidden="true" {...props}>
      <path d="M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z" stroke="currentColor" fill="none" />
    </svg>
  );
}

// Meaningful control — name the button, hide the glyph
<button type="button" aria-label="Search">
  <SearchIcon />
</button>

If the SVG ships a <title> from Figma, keep it only when the icon is the sole label; otherwise remove it to avoid double announcements.

Next.js App Router and RSC

Pasted icon components without hooks are fine as Server Components — they are just JSX. Do not wrap them in next/image. Client boundaries matter only if the icon file imports browser-only APIs (it should not).

Colocate icons under components/icons/, export named components, and let the bundler tree-shake unused files. That scales better than one mega icons.tsx barrel that re-exports everything.

Privacy: why in-browser JSX export matters

Unreleased product icons should not hit a random upload converter. SVGEditor builds React / React Native output in the browser — same stance as preview and PNG. Share links encode the SVG in the URL hash; treat them like the file itself.

Common mistakes

  • Dropping viewBox: the icon stops scaling cleanly when you change width/height. Keep it on the root <svg> / <Svg>.
  • Shipping Figma’s #000 fills: fine on a light mock, invisible or harsh on a dark UI. Prefer currentColor (or theme props) for chrome icons.
  • Using next/image for interactive icons: you lose easy fill / stroke / className control. Use a component (SVGR or pasted JSX).
  • Leaving kebab-case attributes in JSX: stroke-width must become strokeWidth (and friends). Converters catch this; hand edits often miss one.
  • Quoting numeric props in React Native: width="24" should be width={24}. SVGEditor’s RN export already uses numbers.
  • Reusing gradient ids across icons: two components with id="paint0" on one page fight each other. Rename ids per file or inline unique prefixes after export.
  • Pasting a full illustration as JSX: huge path dumps bloat the JS bundle. Keep large art as <img> / static SVG; reserve components for UI chrome.
  • Forcing currentColor on brand logos: flattens multicolor logos. Keep fixed brand fills, or expose named color props for the few paths that should theme.
  • Skipping sanitize on untrusted uploads: converting to JSX does not remove XSS vectors. Sanitize first — see Sanitize untrusted SVG.
  • One mega icons.tsx barrel: harder to tree-shake. Prefer one file per icon under components/icons/.

Production checklist (before you commit)

  • Color: chrome icons use currentColor (or theme props); leave fixed fills only on multicolor logos.
  • Paint mode: stroke icons → stroke="currentColor" + fill="none"; fill icons → fill="currentColor".
  • Size: default width/height, keep viewBox, spread {...props} last.
  • Accessibility: decorative icons get aria-hidden="true"; meaningful controls name the button (or use aria-label), not path soup.
  • Ids: unique gradient / clipPath ids per file — or strip unused defs.
  • Cleanup: remove editor metadata, empty groups, and unused xmlns noise on RN exports.
  • TypeScript: web → React.SVGProps<SVGSVGElement>; RN → types from react-native-svg.
  • Trust: sanitize untrusted SVG before export; never paste raw internet SVG straight into production components.

FAQ

How do I convert an SVG to a React component?

Paste the SVG into SVGEditor’s SVG to React converter, open the React tab, and copy the generated component. Kebab-case attributes become JSX (stroke-width → strokeWidth), and {...props} sits on the root <svg>. Prefer currentColor for themeable UI icons, keep viewBox, and sanitize first if the file was untrusted.

Is there a free SVG to React converter online?

Yes. SVGEditor converts SVG to JSX in your browser for free — no account and no file upload to a server. Paste SVG, keep the React tab open, and copy the component (button at the top of this guide).

How do I convert SVG to JSX for TypeScript?

Paste the SVG into the converter, copy the React export into a .tsx file, and type props as React.SVGProps<SVGSVGElement> so className, onClick, and ARIA attributes stay typed. For design-system icons that need a DOM ref, wrap with forwardRef — see Design-system patterns.

Can I convert SVG to a React Native component?

Yes. Use the React Native tab. It maps tags to react-native-svg (Svg, Path, Circle, …), adds the import, and uses numeric props like width={24}.

Should I use SVG as an <img> or as an inline React component?

Use <img> (or a static asset) for large illustrations you never recolor. Use a component when the same icon appears in buttons, nav, and themes with different colors.

Does the converter change my paths?

SVGEditor rewrites the tree into JSX / RN tags and JSX attribute names. It does not re-path or optimize geometry the way SVGO does — preview first if the SVG is unusual.

SVGR or SVGEditor — which should I use?

Use SVGR when icons are a steady stream of .svg files in the repo. Use SVGEditor when you need a quick JSX / React Native snippet, a live preview, or a share link without touching the bundler.

Should I sanitize SVG before converting to React?

Yes for untrusted uploads or paste from the internet. Sanitize first so script, foreignObject, and hostile SMIL never land in your component tree. SVGEditor sanitizes before preview and export — details in Sanitize SVG for XSS.

Can I share the SVG with a teammate?

Yes — use Copy link or Copy iframe in the editor. The payload lives in the URL hash on their side; treat share links like the file itself.

Related guides

Convert SVG to PNG — retina sizing and transparent downloads when you need a bitmap handoff.
Sanitize SVG for XSS — strip script, foreignObject, and hostile SMIL before preview, share, or React export.

Convert your SVG now

Paste once, confirm the live preview, then export React or React Native — or download PNG / Data URI from the same workspace. Free, no account required.

Open SVG → React converter SVG → PNG
← Back to SVGEditor · SVG to React tool · Download SVG Editor · Best SVG editors · Terms · Privacy