5 min read

The SVG workflow that keeps your React bundle small

How to take a Figma export from 15KB to 400 bytes, convert it into a clean React component, and ship icons without a bloated icon library.

By
Software Engineer ยท M.Sc. Mechanical Engineering ยท Ontario, Canada

Why raw Figma / Illustrator SVGs are enormous

A 24ร—24 icon exported from Figma is often 3-8 KB. The actual visual content - a couple of <path> elements - is 200-400 bytes. The rest is:

  • Editor metadata (sodipodi:namedview, inkscape:... attributes, sketch:type attributes).
  • <title> and <desc> blocks with the layer name.
  • <metadata> block with the app version.
  • Path coordinates written to 8-10 decimal places (M12.00000000 2.00000000).
  • Empty <g> groups from the export step.
  • xmlns:* declarations for namespaces nothing uses.
  • Redundant fill-opacity="1", stroke-opacity="1" attributes.

Ship those raw and every icon in your project pays the tax.

The passes that actually matter

Optimization passes ranked by size impact on typical Figma exports:

  1. Round path decimals. M12.00000000 2.00000000 โ†’ M12 2. Biggest single win - often 40-50% of the file.
  2. Strip metadata + editor namespaces. 15-25% more.
  3. Remove empty groups. 5-10%.
  4. Collapse whitespace. 5-10%.
  5. Remove default attributes. Small but free.

Together: a typical 5KB Figma icon becomes 400-800 bytes with zero visual change.

SVG Optimizer runs all six passes with toggles and shows before/after size. Everything runs in-browser via string manipulation - no server round-trip.

When to be careful with decimal precision

The default 2-decimal precision is safe for icons. Below 1 decimal, tight curves can visibly deform. If your SVG is a complex illustration (a logo mark with subtle curves, an infographic), keep precision at 2 or 3.

For UI icons (Lucide, Heroicons, Phosphor scale), 1-decimal precision is imperceptible and saves another 10-15%.

SVG in React: three approaches

1. <img src="/icon.svg" />. Simplest. External file, cached separately. Loses reactivity - you can't change the color from a prop, and the icon may flash on load.

2. Inline SVG as a React component. Full control - pass color as a prop, animate paths, apply CSS. This is what every serious icon library does.

3. SVG sprite (<use xlinkHref="#icon-foo" />). All icons in one file, referenced by ID. Good for very large icon sets; annoying to maintain by hand.

Most React projects should default to option 2. Costs a few bytes per icon; unlocks styling, animation, and no network request.

Converting SVG โ†’ React component

The transforms:

  • class โ†’ className
  • Kebab-case attributes โ†’ camelCase (stroke-width โ†’ strokeWidth, fill-rule โ†’ fillRule)
  • style="color: red" โ†’ style={{ color: "red" }}
  • Root <svg> forwards props so <Icon className="foo" onClick={...} /> works
  • Optional React.memo wrap for pure components
  • Optional TypeScript typing (React.SVGProps<SVGSVGElement>)

Doing this by hand for one icon is fast. Doing it for a hundred is where automation earns its keep.

SVG to JSX applies all transforms in one paste - pick a component name, choose TypeScript or JavaScript, choose whether to wrap in React.memo, and copy.

The two-step workflow for building an icon set

The pattern that produces the smallest React bundle:

  1. Design each icon at 24ร—24 in Figma. Export as SVG.
  2. SVG Optimizer - every icon through the optimizer. Typical 5KB โ†’ 500 bytes.
  3. SVG to JSX - convert each optimized SVG to a React component. Paste, copy, save to a file.
  4. Re-export them from an icons/index.ts so consumers can import { ChevronRight } from "@/icons".

Result: an icon set of 50-100 icons that costs 20-50KB total - smaller than a single icon library import.

When not to build your own icon set

Icon libraries earn their weight when:

  • You need 500+ icons.
  • The maintainer keeps them visually consistent (stroke width, corner radius, style).
  • You use tree-shaking so only imported icons ship.

Lucide, Heroicons, Phosphor, Tabler, and Radix Icons all handle these well. Tree-shaking works if you import individually (import { ChevronRight } from "lucide-react"), not from a barrel.

The break-even point: if you need fewer than 20-30 icons, build your own. More than that, use a library.

Related tools

Tools mentioned in this post

Written by Shan

Shan builds 712 Tools. He holds a Master's degree in Mechanical Engineering and now works as a Software Engineer, shipping browser-based developer utilities out of Ontario, Canada. Learn more ยท 712studiogames@gmail.com