SVGFlow
Open editor

SVG to Svelte component

Convert SVG to a Svelte component: the markup as-is, with {...$$restProps} spread on the root after the file’s own attributes, so anything the caller passes — class, width, fill — wins.

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
FileIcon.svelte

How to convert SVG to a Svelte component

Drop an SVG file or paste markup, and the output is the same markup, pretty-printed, with exactly one addition: {...$$restProps} on the root <svg>, inserted after the file's own attributes. There is no script block, no imports, no wrapper element — Svelte compiles the file directly, so an icon component genuinely is just its markup. The conversion is a local parse and re-print in your browser; nothing you drop here is uploaded.

Svelte accepts SVG attributes in their native kebab-case, so unlike JSX nothing is renamed — stroke-linecap, fill-rule and friends pass through letter for letter. And because a Svelte component has no name of its own, the name you type here only decides the download's file name: ArrowLeft.svelte is what makes it <ArrowLeft /> at the import site. XML comments survive the re-print too, so a licence header stays with its artwork.

What $$restProps buys, and where it stops

$$restProps is every prop passed to the component that it did not declare — which, for a component with no script block, is all of them. Spreading it on the root means <ArrowLeft width="16" class="nav-icon" /> puts both attributes on the <svg> without any prop declarations. The spread is placed after the file's attributes deliberately: later attributes win in Svelte, so the caller can override the exported width, fill or anything else. The flip side is that class replaces rather than merges — if the file carries a meaningful class of its own, merge explicitly with class="icon {$$props.class ?? ''}".

The boundary worth knowing in Svelte 3 and 4: $$restProps carries props, not event listeners. A on:click on the component does not reach the <svg> through the spread — forward it by writing a bare on:click inside the component, or handle clicks on a wrapping button, which is usually the more accessible shape anyway. In Svelte 5, event handlers are ordinary props (onclick), so a runes-mode spread forwards them like everything else. The Svelte guide goes through both models.

Svelte 5 and runes mode

The emitted {...$$restProps} works in Svelte 3, Svelte 4 and Svelte 5's legacy mode, which is why it is the default output. In a runes-mode component, $$restProps is a compile error; the replacement is two lines — a script block with let { ...rest } = $props() and {...rest} in place of the old spread. That version also picks up Svelte 5's event-handlers-as-props behaviour, so onclick passed by a caller lands on the svg with no forwarding ceremony. If your project mixes modes, leave icons in legacy form until the file around them flips — the compiler treats each component independently.

Sizing, colour and labels at the call site

Everything configurable about the icon is configured where it is used. Size: width and height through the spread, or CSS on the component selector. Colour: convert fills to currentColor with the Color Replacer before converting and the icon inherits the CSS color of whatever contains it — one icon file serves light mode, dark mode and hover states without variants. Accessibility rides the same spread: aria-hidden="true" for decorative uses, role="img" plus aria-label when the icon is the content — patterns covered in the accessible icons guide. None of this needs to be designed into the component, which is the quiet advantage of the spread-only approach: the icon file stays a dumb drawing, and every decision about how it appears is made — and reviewable — at the place it is used.

Common problems

  • Svelte 5 runes mode rejects $$restProps. Expected — destructure instead: let { ...rest } = $props(), then spread {...rest}. The emitted form is for Svelte 3, 4 and 5's legacy mode.
  • on:click on the component does nothing. In Svelte 3/4 listeners are not props, so the spread cannot forward them. Add a bare on:click to the <svg> inside the component to forward it, or wrap the icon in a <button>.
  • A caller's class replaces the file's class. The spread is last, so it overrides rather than merges — that is what makes caller overrides work. Merge explicitly when the internal class matters.
  • Duplicate gradient ids across icons. Ids are page-global in every framework; two icons sharing #grad resolve to whichever mounted last. Prefix defs ids per component before converting.

When a component per icon is too many components

Svelte components are cheap — compiled, not interpreted — but they are not free: each icon is a module resolved and its output shipped, used or not, unless your bundler tree-shakes the import away. For a couple of dozen active icons that is the right trade. For a long tail of rarely shown glyphs, one sprite plus <use href="#name" /> in plain markup ships a single cacheable document and zero per-icon JavaScript. Decorative shapes that never change can skip markup entirely as CSS data URIs. And whichever route an icon takes, put it through the Optimizer first — the converter preserves the file faithfully, editor cruft included.

Questions

Is this SVG to Svelte converter free?

Yes — no account, no watermark, no cap on how many icons you convert. The site is funded by advertising.

Is anything uploaded when I convert?

No. The SVG is parsed and re-printed by the page running in your browser. There is no server-side step at any point.

What exactly does the converter change in my SVG?

One thing: it adds {...$$restProps} to the root <svg> tag, after the existing attributes. The rest of the output is your markup pretty-printed. Svelte accepts kebab-case SVG attributes natively, so no renaming is needed.

Why is there no <script> block in the output?

Because the component does not need one. It declares no props — $$restProps forwards whatever the caller passes — and holds no state. A Svelte component can be markup alone, and for icons that is the whole job.

How do I name the component?

By the file name. Svelte components are anonymous inside; saving as ArrowLeft.svelte is what lets you write <ArrowLeft />. The name field on the tool sets the download’s file name for exactly this reason.

Does the output work in Svelte 5?

In legacy mode, yes, unchanged. In runes mode, replace $$restProps with a rest destructure from $props() — two lines. Svelte 3 and 4 use the output as-is.

Why does on:click on my icon component not fire?

In Svelte 3 and 4, event listeners are not props, so the $$restProps spread cannot forward them. Add a bare on:click inside the component to forward the event, or wrap the icon in a button. In Svelte 5 runes mode, onclick is a prop and spreads through.

How do I make the icon follow my text colour?

Replace its hard-coded fills with currentColor — the Color Replacer has a one-click conversion — then control it with the CSS color property. One component then covers themes, hover and disabled states without duplicate files.

Can I override the width, height or fill from the caller?

Yes — that is what the spread’s position is for. It sits after the file’s own attributes, and in Svelte the later attribute wins, so anything you pass replaces the exported default.

Does it work in SvelteKit?

Yes. The component is plain markup with no browser-only code, so it server-renders in SvelteKit without any load-time guards.

Should I optimize the SVG before or after converting?

Before. The converter preserves the file faithfully — including editor metadata and over-precise paths if they are there. Cleaning up afterwards means editing a component; cleaning up first is one pass through the Optimizer.

Notes

  • A Svelte component is its own file, so the component name is the file name — nothing inside the markup carries it.
  • $$restProps works in Svelte 3 and 4, and in Svelte 5’s legacy mode. For runes mode, swap it for a {...rest} from $props().
  • Svelte keeps SVG attributes kebab-case, so the body needs no rewriting at all.

Related tools