SVG Cleaner and Component Generator

Paste SVG or choose a file, then clean it and select a component target. Review the preview because removing metadata, active elements or attributes can change the SVG.

Runs locally in your browser
Everything in this tool is processed in this browser. VoriTools does not upload, store, or call a third-party API with your input.
SVG sourcePaste SVG markup or select a local .svg file. Script-capable and remote-content elements are removed before preview or code generation.

How to clean an SVG and turn it into a React, Vue or Svelte component

This page cleans SVG markup in the browser and prints the same drawing as a React, Vue or Svelte component. Paste markup or choose a local .svg file, and the preview, the byte counters and the generated code all come from the cleaned element. Nothing is uploaded, and the page keeps working with the network switched off.

The cleanup is conservative about the drawing and strict about everything that can run or fetch: coordinates, ids, class names and local CSS are kept exactly as written, while scripts, animation elements, event attributes and remote references are removed. Check the preview before you use the result, because dropping an animation or a remote style rule changes what the file does.

  1. Paste SVG markup into the text area, or choose a .svg file — a chosen file is read and cleaned straight away.
  2. Press Optimize SVG. The output panel shows the cleaned markup, the preview renders it as an image, and the three tiles report input bytes, output bytes and the viewBox.
  3. Compare the preview with the original artwork: animation, metadata and remote references are gone, so a heavily styled icon can look different afterwards.
  4. Type a component name, choose React, Vue or Svelte, then press Generate component; the output panel switches to the component source for the same cleaned SVG.
  5. Copy or Download takes the current output — cleaned markup as .svg, a component as .jsx, .vue or .svelte, named after the component field. Clear empties the input, the file picker and the result.

What the cleanup changes, what it leaves alone, and what the components assume

What the cleanup removes, keeps and rewrites

Removed: <script>, <foreignObject>, <iframe>, <object>, <embed>, <audio>, <video> and the animation elements <animate>, <animateMotion>, <animateTransform> and <set>; every on* event attribute; href and xlink:href values that are not internal #id references; any attribute whose value calls a remote url(); <style> blocks that @import or call a remote url(); comments, <metadata> and <desc>. Kept: path data, ids, class names, presentation attributes such as rx, opacity and transform, and CSS that only points inside the file. In testing url(#g1) survived while style="fill:url(https://…)" did not.

Rewritten: a root without a viewBox gets one from its width and height, or 0 0 24 24 when neither is present; width and height are then dropped, xmlns is set, and whitespace between tags is collapsed. It is not a minifier — numbers are left alone, so a path that reads "M 4.000 4.0" keeps its zeros, and a small icon can grow once viewBox and xmlns are added. The example icon went from 310 to 248 bytes, and the tiles count UTF-8 bytes, so a CJK label is counted as the bytes it really takes.

The React, Vue and Svelte output

React output is a function component that spreads {...props} onto the root, and attribute names are converted where the framework expects it: class becomes className and stroke-linecap, fill-opacity, font-size, text-anchor, stop-color or clip-path become camelCase, so the component does not print invalid-DOM-property warnings. Quoted values and CSS inside <style> are left as they are, and an icon with no children becomes a self-closing <svg … {...props} />.

Vue output is a single-file component with <script setup>, defineProps({ size }) and :width/:height bound to size; Svelte output uses export let size with width={size} height={size}. Both add aria-hidden, and React sets no size at all — its root keeps only the viewBox, so pass width and height as props or size it with CSS. The name field becomes a PascalCase identifier: an empty field is KivIcon, and a name that cannot start an identifier is prefixed, so 3d-icon exports Svg3dIcon.

Limits to know before you rely on it

There is no path optimisation and no id rewriting: two icons that both define id="g1" still collide on one page, exactly like hand-written SVG. Animation is deleted rather than preserved, and a <style> block that mixes a local rule with a remote url() is dropped whole, so check the preview when the original relied on a linked stylesheet.

The preview is an <img> fed by a blob URL, so scripts inside the markup cannot run; that makes it a faithful view of the cleaned file rather than a security audit. Invalid input is reported and the previous result is cleared instead of left on screen: the text needs exactly one <svg> root, and an undefined XML entity such as &nbsp; is rejected because an SVG is parsed as XML — &#233; and the five predefined entities are accepted.

Recent tools: