How to generate vue 3 and svelte svg components from raw svg
- Step 1Drop in one SVG or paste the markup — Drag a single
.svgonto the tool, click to browse, or paste raw<svg>markup into the text box (visible when no file is selected). This is a single-file tool — there is no multi-file picker here. Free tier accepts up to 5 MB, Pro up to 50 MB, Developer up to 2 GB per file (icons are kilobytes, so the cap only matters for huge generated art). - Step 2Choose Vue 3 or Svelte — The Framework dropdown has exactly two options:
Vue 3andSvelte. Vue produces a.vueSFC (<template>+<script setup>); Svelte produces a.sveltefile (<script>then markup). There is no Options-API choice and no Angular/React option here — for React, use the sibling SVG to JSX tool. - Step 3Set the component name (optional) — Type a name in the Component name field, or leave it blank to use the uploaded file's stem. The name appears in the leading
<!-- Generated component: NAME -->banner and, for Vue, drives the suggested.vuefilename (kebab-cased). It does not generate aname:field or named TypeScriptPropsexport. - Step 4Decide on TypeScript — Leave the TypeScript checkbox on (default) for
<script lang="ts">with typed props, or uncheck it for a plain JavaScript block. In Vue+JS mode the props get runtimedefineProps({ size: { type: [Number, String], default: 24 }, ... })defaults; in Vue+TS mode they're a type-onlydefineProps<{ size?: ... }>(). - Step 5Process and review the output — Click Process SVG. The result panel shows the generated component text. Read it before pasting: confirm whether you actually need the
size/colorprops wired (the tool leaves your SVG's literal dimensions and colours in place), and that the markup looks intact after comment-stripping. - Step 6Copy or download and wire the props yourself — Copy the snippet or download the
.vue/.sveltefile into your component folder. To makesizeandcoloractually do something, bind them in the markup yourself — e.g. Vue:width="size"/:fill="color", Sveltewidth={size}/fill={color}. See the cookbook for the exact edits.
The three options this tool exposes
These are the only controls in the UI and the only fields in the API schema for svg-to-vue-svelte. Anything else (slots, ARIA props, style blocks, template overrides) is not generated.
| Option | Type | Default | What it changes |
|---|---|---|---|
framework | enum vue / svelte | vue | Picks the output file shape: Vue 3 <script setup> SFC vs Svelte <script> + markup |
componentName | string | file stem | Sets the name in the Generated component banner; for Vue it also kebab-cases the suggested .vue filename |
typescript | boolean | true | On → lang="ts" with typed props; off → plain JS block (Vue gets runtime defineProps({...}) defaults instead of a type) |
What the generated Vue vs Svelte component actually contains
Both outputs declare the same three props but neither binds them to your SVG — the markup is inserted verbatim. The differences are purely in the framework boilerplate.
| Aspect | Vue 3 output | Svelte output |
|---|---|---|
| Wrapper | <template> around the SVG, then <script setup> | <script> block, then the SVG as plain markup |
| Props declared | size?, color?, class? via defineProps | size = 24, color = 'currentColor', className = '' via export let |
| Props bound to SVG? | No — class lands on the SVG via Vue attribute fallthrough; size/color are unwired | No — none of the three are referenced in the markup |
| TypeScript form | defineProps<{ size?: number | string; color?: string; class?: string }>() | export let size: number | string = 24; etc. |
| Banner / name | <!-- Generated component: NAME --> at the top | <!-- Generated component: NAME --> at the top |
| Style block | None emitted | None emitted |
Cookbook
Real before/after snippets. The tool gives you the shell; these show the one or two lines you add to make the props live.
A search icon → Vue 3 TS component (default output)
This is exactly what the tool emits for a basic icon with framework: vue, typescript: true. Note the literal width/height/stroke survive — the props are declared but not yet used.
Input search.svg:
<svg width="24" height="24" viewBox="0 0 24 24" stroke="#000" fill="none">
<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>
</svg>
Tool output (search.vue):
<!-- Generated component: search -->
<template>
<svg width="24" height="24" viewBox="0 0 24 24" stroke="#000" fill="none">
<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>
</svg>
</template>
<script lang="ts" setup>
defineProps<{
size?: number | string
color?: string
class?: string
}>()
</script>Make the size and color props actually work (Vue)
The tool stops at declaring the props. To make them reactive, edit the <svg> to consume them. This is the manual step the generator does not perform.
Edit the generated <template> by hand:
<template>
<svg :width="size" :height="size" viewBox="0 0 24 24"
:stroke="color" fill="none">
<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>
</svg>
</template>
Now <Search :size="32" color="#6366f1" /> resizes and recolours.
The class prop already works via Vue fallthrough:
<Search class="opacity-50" /> lands on the root <svg>.Same icon → Svelte component
Svelte output for framework: svelte, typescript: true. Props use export let; className (not class, a reserved word) is the styling prop.
Tool output (search.svelte):
<!-- Generated component: search -->
<script lang="ts">
export let size: number | string = 24;
export let color: string = 'currentColor';
export let className: string = '';
</script>
<svg width="24" height="24" viewBox="0 0 24 24" stroke="#000" fill="none">
<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>
</svg>
To wire it, edit the markup yourself:
<svg width={size} height={size} stroke={color} class={className} ...>JavaScript (no TypeScript) Vue output
Unchecking TypeScript switches Vue from a type-only defineProps to runtime declarations with defaults — useful when your build has no TS pipeline.
Tool output (typescript: false):
<!-- Generated component: search -->
<template>
<svg ...>...</svg>
</template>
<script setup>
defineProps({
size: { type: [Number, String], default: 24 },
color: { type: String, default: 'currentColor' },
class: { type: String, default: '' },
})
</script>Clean the SVG first for a smaller component
The converter inserts your markup verbatim (minus comments). Editor cruft from Figma/Illustrator stays unless you strip it first. Run a cleanup pass, then convert.
Recommended pipeline before this tool: 1. /svg-tools/svg-metadata-scrubber -> drop <metadata>, editor IDs 2. /svg-tools/svg-pro-minifier -> collapse whitespace, shorten paths 3. /svg-tools/svg-to-vue-svelte -> wrap the clean SVG Result: the <template>/markup contains only the geometry, so the committed component diff is tiny and readable.
Edge cases and what actually happens
size and color props don't change the icon
By designThe most common surprise: you pass :size="40" and nothing happens. The tool declares size/color but never references them in the markup — your original width/height/stroke/fill are still hard-coded. Bind the props yourself (see the cookbook), or switch the colours to currentColor first with SVG to Tailwind so color can drive them via CSS.
Multiple SVGs at once
Single file onlyThis tool accepts exactly one file or one pasted markup blob — the only multi-file SVG tool is the sprite builder. To convert a whole icon set, drive the tool from a script via the API/runner one file at a time (see the batch-generation guide), or convert each icon individually in the UI.
SVG won't parse / not valid XML
Invalid inputPasted content is validated as SVG XML before processing; malformed markup (unclosed tags, an HTML fragment, an <img> reference to an SVG) is rejected with an Invalid SVG error. Fix the source — a real <svg> root with balanced tags — and retry. The tool does not repair broken markup.
Comments inside the SVG disappear
ExpectedAll <!-- ... --> comments are stripped before wrapping. License banners or layer notes embedded as comments will not survive into the component. If you must keep a licence, add it back to the generated file outside the markup, or keep the licence in a separate LICENSE file in your icon package.
You expected slots, ARIA props, or event handlers
Not generatedThe output has no <slot>, no aria-label/role props, and no @click/on:click forwarding — only size, color, and class/className. Add accessibility attributes and handlers yourself after generation. There is no option to inject them.
Vue class prop collides with attribute fallthrough
PreservedVue declares class? and also applies any passed class to the single root <svg> automatically (attribute fallthrough). In practice class works without you binding it. If your root SVG already has a literal class="...", the consumer's class merges with it per Vue's normal rules — nothing is dropped.
Component name has spaces or odd characters
NormalisedFor Vue, the name is kebab-cased for the suggested filename (spaces and capitals become hyphens). The banner uses the name you gave. If you need a strict PascalCase component identifier in code, rename it after download — the tool does not enforce a casing convention on the in-code reference.
Huge generated/auto-traced SVG
Tier-limitedFiles above your tier cap are rejected (Free 5 MB, Pro 50 MB, Developer 2 GB). Hand-drawn icons never approach this, but a traced photo or a dense mesh can. Simplify first with SVG Path Simplifier and minify with SVG Pro Minifier before wrapping.
Output has no <style> block
ExpectedNeither Vue nor Svelte output includes a <style>/<style scoped> block. Styling is meant to flow through the class/className prop and CSS, not scoped CSS. If your design system wants scoped styles, add the block to the downloaded file manually.
You wanted React instead
Wrong toolThis tool only targets Vue 3 and Svelte. For React .jsx/.tsx (with attribute conversion like class → className, stroke-width → strokeWidth, and {...props} spread), use SVG to JSX instead.
Frequently asked questions
Does the Vue output use the Options API or Composition API?
Composition API only. The tool emits Vue 3 <script setup> with defineProps — there is no Options-API toggle. <script setup> is the recommended modern shape and works in any Vue 3.2+ / Vite / Nuxt 3 project.
Do the size and color props actually resize and recolour the icon?
Not on their own. The tool declares size and color but leaves your SVG's literal width/height and fill/stroke in place — it does not bind the props to the markup. You make them live by editing the <svg> to use :width="size"/:stroke="color" (Vue) or width={size}/stroke={color} (Svelte). The cookbook shows the exact edit.
Does the Svelte output support TypeScript?
Yes. With the TypeScript checkbox on (default), Svelte gets <script lang="ts"> and typed export let props (size: number | string = 24, color: string = 'currentColor', className: string = ''). It works in SvelteKit with the standard svelte-preprocess setup.
What props are on the generated component?
Exactly three. Vue: size, color, class. Svelte: size, color, className (since class is reserved in Svelte script). Defaults are 24, currentColor, and empty. There are no aria-label, role, title, or slot props — add those yourself if you need them.
Can I convert a whole folder of icons at once?
Not in the browser UI — it's single-file (one upload or one paste). For a set, script the conversion through the API/runner one file at a time; the batch-generation guide shows the loop. The only multi-file SVG tool in the suite is the sprite builder, which solves a different problem.
Can I use these in Nuxt 3?
Yes. The Vue SFCs are standard <script setup> components — drop them in components/ and Nuxt auto-imports them. Because the icon is inlined in the template, it renders server-side with no flash of missing content. Remember to wire size/color if you want them reactive.
Can I use the Svelte output in SvelteKit?
Yes. The .svelte file is a plain component with export let props; import it anywhere in a SvelteKit route or library. It renders inline on the server during SSR. The className prop is how you pass classes (Svelte reserves class).
Are my SVGs uploaded to a server?
No. In the browser the conversion runs locally and nothing is sent. If you automate it via the API, execution happens on your own machine through the paired @jadapps/runner — the JAD /api/v1/tools/.../run endpoint is upload-free and never receives file content.
Does it strip anything from my SVG?
It removes XML/editor comments and trims surrounding whitespace, then inserts the rest of the markup verbatim. It does not minify paths, scrub metadata elements, or rewrite attributes. To slim the icon first, run SVG Metadata Scrubber and SVG Pro Minifier before converting.
Why is this a Developer-tier tool?
Vue/Svelte component generation is gated to the Developer plan; React JSX/TSX via SVG to JSX is available on Pro. Free and Pro users see an upgrade prompt on this tool.
Can I customise the component template the tool uses?
No. The wrapper shape is fixed (banner, <template>/<script setup> for Vue; <script> + markup for Svelte). There is no template-override field. If you need a different shell — extra props, a style block, ARIA — edit the downloaded file or post-process it in your build.
Does it export a named Props type I can import?
No. Vue uses an inline defineProps<{...}>() generic with no exported Props type, and Svelte types props inline on each export let. If you want a reusable Props type, declare it yourself and reference it in the generated file.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.