Formats

SVG vs PNG Icons: Choosing the Right Format

F

Freeicon

Freeicon Editorial

Apr 23, 2026
4 min read
SVG vs PNG Icons: Choosing the Right Format

Picking between SVG and PNG for icons sounds like a small decision until your interface ships at 3x density on a Retina display and the artwork falls apart. Most product teams default to one format out of habit, then fight the consequences for years. The choice is actually pretty mechanical once you understand what each format does well, where it breaks down, and what your build pipeline is willing to do with it.

What actually separates SVG from PNG

PNG is a raster format. Every icon is a fixed grid of pixels, baked at export time. Scale a 24px PNG up to 96px and the browser stretches those pixels, producing the soft, blurry edges every designer recognizes. SVG is the opposite. It stores shapes as math (paths, circles, polygons) inside an XML file, which means the browser redraws the icon at whatever size you ask for. A 16px favicon and a 400px hero illustration can come from the same source.

That difference cascades into almost every other tradeoff. SVGs are usually smaller for simple icons because a few path commands compress better than thousands of pixels. They can be styled with CSS, animated with JavaScript, and inspected in DevTools like any other DOM node. PNG holds its ground when artwork has photographic detail, soft gradients, or noise patterns that would bloat an SVG file with hundreds of nodes. For UI iconography, SVG is the obvious default. For screenshots, illustrations with shading, or anything resembling a photograph, PNG (or WebP) still earns its place.

Exporting clean SVGs from Figma

Figma's SVG export is good but not magical. The output reflects whatever you drew, including hidden layers, mask groups, and stroke effects that don't translate cleanly to the web. A few habits keep your exports tidy:

  • Flatten strokes to fills before exporting. Open paths with stroke widths render inconsistently across browsers, especially when you scale them.
  • Use a single frame per icon, sized to your design grid (24x24 is common). Set the frame to clip content so nothing leaks outside the viewBox.
  • Name layers semantically. Figma writes layer names into the SVG as id attributes, which is genuinely useful when you need to target a specific path with CSS.
  • Run the exported file through SVGO or a similar optimizer. Figma leaves metadata, empty groups, and overprecise decimal values that double the file size for no benefit.

Select the icon frame, choose SVG in the Export panel, and tick Outline text if your icon includes any type. For a project of more than a handful of icons, set up an automated pipeline so exports stay consistent across the team and nobody is hand-tweaking files in pull requests.

Picking a format for mobile apps

Mobile is where the SVG default starts to wobble. iOS supports SVG through WebKit and through PDF assets, but UIKit has historically treated raw SVG as a second-class citizen. Android handles SVG through Vector Drawables, which the build tool converts at compile time. Both platforms work fine with SVG sources, but the runtime asset is often something else: a vector drawable, a PDF, or a set of PNGs exported at 1x, 2x, and 3x.

The practical answer is to design in SVG and export to whatever the platform prefers. For a React Native app, libraries like react-native-svg let you ship the SVG directly. For a native iOS or Android codebase, lean on the platform's vector format and only fall back to PNG when an icon has effects (drop shadows, gradient noise, photographic textures) the vector format can't reproduce. PNG bundles also make sense when you have to support older OS versions where vector rendering is unreliable.

Licensing without surprises

SVG itself is a file format, so the format isn't licensed at all. What matters is the license attached to the artwork. Some popular icon sets restrict commercial use, require attribution, or charge per seat for team accounts. Others are genuinely free for any project. Read the license before you commit a folder of icons to your repo, because swapping an icon set after launch is painful and usually involves redrawing custom variants.

If you want to skip the license review entirely, FreeIcon publishes free SVG and PNG icons that work for personal and commercial projects with no attribution and no signup. That covers most of the cases where teams hit a licensing snag halfway through a build.

Inlining SVGs in React and HTML

For a static HTML page, the simplest approach is to paste the SVG markup directly into the document. The browser treats it like any other element, so you can target paths with CSS, attach event listeners, and animate properties without loading a separate file. The tradeoff is bigger HTML and no caching, which adds up if the same icon appears on every page. A common compromise is to inline a sprite sheet once at the top of the body and reference symbols with the use element.

In React, you have three reasonable options. You can import the SVG as a component using a tool like SVGR (built into Create React App and most modern bundlers), which gives you full control over props, className, and event handlers. You can paste the SVG markup inline as JSX, which works well for a small set of icons that rarely change. Or you can load the file as a URL and drop it into an img tag, which is the easiest path but blocks CSS styling of the icon's interior. Most teams end up using SVGR for shared icon components and inline JSX for one-offs.

Whichever route you pick, control width, height, and fill through CSS rather than hardcoding them in the SVG. That way a single icon component can adapt to dark mode, hover states, and size variants without a dozen near-duplicate files. Your designers will thank you the first time they ask for a color change and you ship it in one line of CSS.