PeterShershov/vite-svgee-plugin

Import SVG files as React components in Vite with zero runtime overhead

TypeScript

0

2 commits

updated Oct 18, 2026

See the code

See what people are saying

README

CI

vite-svgee-plugin

vite-svgee-plugin

Import SVG files as React components in Vite with zero runtime overhead.

import ArrowLeft from "./icons/arrow-left.svg?react";

<ArrowLeft className="icon" onClick={handleClick} />;

Setup

Requires Vite ≥ 7.

// vite.config.ts
import svgee from "vite-svgee-plugin";

export default defineConfig({ plugins: [svgee()] });

Each imported SVG is typed as (props: SVGProps<SVGSVGElement>) => ReactNode. Pull in the ambient declaration for *.svg?react the same way you would vite/client - either in a .d.ts file:

/// <reference types="vite-svgee-plugin/client" />

or via compilerOptions.types in your tsconfig.json:

{ "compilerOptions": { "types": ["vite-svgee-plugin/client"] } }

Options

svgee({
  svgo: {
    /* SVGO config */
  }, // or false to disable. Requires `svgo` to be installed.
  forwardRef: false, // wrap with React.forwardRef, forwarding ref to the root <svg>
  memo: false, // wrap with React.memo, can be combined with `forwardRef`
  dimensions: true, // set to false to strip width/height from the root <svg>
});

How it works

When a module ID matches *.svg?react, the plugin:

  1. Reads the SVG file from disk
  2. Parses the XML into an element tree with a character-level parser
  3. Emits a JS module that default-exports a React component built from createElement calls

The SVG's original attributes are merged with props passed at the call site, so overriding className, aria-label, event handlers, etc. all work as expected.

// generated output (simplified)
import { createElement as h } from "react";
export default function SvgArrowLeft(props) {
  return h("svg", { viewBox: "0 0 24 24", ...props }, h("path", { d: "..." }));
}

Parser

The XML parser (src/parse.ts) is purpose-built for SVG, handling:

  • Elements, attributes, text nodes, CDATA, comments, PIs, and DOCTYPE
  • XML entities and character references (&amp;, &#x41;, &#65;)
  • Well-formedness errors: mismatched tags, duplicate attributes, bare &, < in attribute values

Attribute conversion

A static lookup table (~200 entries) maps HTML/SVG attribute names to their React JSX equivalents.

Benchmark

TL;DR: on default settings svgee converts a typical icon in ~0.071 ms against svgr's ~0.38 ms — about 5× faster. With SVGO off on both sides, ~0.021 ms against ~0.33 ms — about 16×.

Each plugin converts the same four SVG files 1,000 times. We take the middle time of those runs, so one slow run cannot skew the result.

Results

Time to convert one file, in milliseconds.

Without SVGO:

Filesvgeesvgrspeedup
tiny.svg0.0210.32715.6×
small-icon.svg0.0210.32815.6×
medium-icons.svg0.0860.8149.5×
stress-heavy.svg0.6295.4278.6×

With SVGO - using the same SVGO settings:

Filesvgeesvgrspeedup
tiny.svg0.0710.3815.4×
small-icon.svg0.1540.4673.0×
medium-icons.svg0.8251.5581.9×
stress-heavy.svg6.20910.0781.6×

Run it yourself:

npm run bench

License

MIT

plugin
svg
vite

PeterShershov/vite-svgee-plugin

Import SVG files as React components in Vite with zero runtime overhead

TypeScript

0

2 commits

updated Oct 18, 2026

See the code

See what people are saying

README

CI

vite-svgee-plugin

vite-svgee-plugin

Import SVG files as React components in Vite with zero runtime overhead.

import ArrowLeft from "./icons/arrow-left.svg?react";

<ArrowLeft className="icon" onClick={handleClick} />;

Setup

Requires Vite ≥ 7.

// vite.config.ts
import svgee from "vite-svgee-plugin";

export default defineConfig({ plugins: [svgee()] });

Each imported SVG is typed as (props: SVGProps<SVGSVGElement>) => ReactNode. Pull in the ambient declaration for *.svg?react the same way you would vite/client - either in a .d.ts file:

/// <reference types="vite-svgee-plugin/client" />

or via compilerOptions.types in your tsconfig.json:

{ "compilerOptions": { "types": ["vite-svgee-plugin/client"] } }

Options

svgee({
  svgo: {
    /* SVGO config */
  }, // or false to disable. Requires `svgo` to be installed.
  forwardRef: false, // wrap with React.forwardRef, forwarding ref to the root <svg>
  memo: false, // wrap with React.memo, can be combined with `forwardRef`
  dimensions: true, // set to false to strip width/height from the root <svg>
});

How it works

When a module ID matches *.svg?react, the plugin:

  1. Reads the SVG file from disk
  2. Parses the XML into an element tree with a character-level parser
  3. Emits a JS module that default-exports a React component built from createElement calls

The SVG's original attributes are merged with props passed at the call site, so overriding className, aria-label, event handlers, etc. all work as expected.

// generated output (simplified)
import { createElement as h } from "react";
export default function SvgArrowLeft(props) {
  return h("svg", { viewBox: "0 0 24 24", ...props }, h("path", { d: "..." }));
}

Parser

The XML parser (src/parse.ts) is purpose-built for SVG, handling:

  • Elements, attributes, text nodes, CDATA, comments, PIs, and DOCTYPE
  • XML entities and character references (&amp;, &#x41;, &#65;)
  • Well-formedness errors: mismatched tags, duplicate attributes, bare &, < in attribute values

Attribute conversion

A static lookup table (~200 entries) maps HTML/SVG attribute names to their React JSX equivalents.

Benchmark

TL;DR: on default settings svgee converts a typical icon in ~0.071 ms against svgr's ~0.38 ms — about 5× faster. With SVGO off on both sides, ~0.021 ms against ~0.33 ms — about 16×.

Each plugin converts the same four SVG files 1,000 times. We take the middle time of those runs, so one slow run cannot skew the result.

Results

Time to convert one file, in milliseconds.

Without SVGO:

Filesvgeesvgrspeedup
tiny.svg0.0210.32715.6×
small-icon.svg0.0210.32815.6×
medium-icons.svg0.0860.8149.5×
stress-heavy.svg0.6295.4278.6×

With SVGO - using the same SVGO settings:

Filesvgeesvgrspeedup
tiny.svg0.0710.3815.4×
small-icon.svg0.1540.4673.0×
medium-icons.svg0.8251.5581.9×
stress-heavy.svg6.20910.0781.6×

Run it yourself:

npm run bench

License

MIT

plugin
svg
vite

Project health

Latest release

1.0.1 · Oct 13, 2026

Releases this year

2