Shipnative
ShipnativeShipnative
Sign in
GuideSeptember 2026 · 10 min read

React Native SVG: Icons, Imports, and Gotchas

react-native-svg is one of the few packages almost every React Native app ends up with, usually indirectly — charting libraries, icon sets, and progress rings all render through it. Then you try to use it directly, drop in an SVG your designer exported, and get a blank square. This guide covers the install, the Metro config that lets you import .svg files as components, how to recolour icons with one prop, and the four reasons a perfectly valid SVG renders as nothing at all.

Install and first shape

npx expo install react-native-svg

Use expo install, not npm install. This package has a native side, and a version that does not match your SDK produces a red screen about a missing native module rather than anything that names the real problem. It ships inside Expo Go, so no development build is required.

There is no <img> here. An SVG is described as components, and each element becomes a real native view:

import Svg, { Path } from 'react-native-svg';

export function CheckIcon({ size = 24, color = '#fb923c' }) {
  return (
    <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
      <Path
        d="M20 6L9 17l-5-5"
        stroke={color}
        strokeWidth={2}
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </Svg>
  );
}

viewBox is the coordinate system the path was drawn in; width and height are the size on screen. Keep both. Omit the viewBox and the path is drawn at its original scale in a box that may be much smaller. Omit width and height and the whole thing lays out at zero and disappears.

ElementWhat it doesIn practice
SvgRoot — needs width, height, and viewBoxEverything else nests inside
PathAny shape, from the d attribute95% of exported icons
Circle / Rect / LineSimple primitivesHand-drawn shapes, rings, bars
GGroup with shared transform or fillCheaper than repeating props
Defs + LinearGradientReusable paint definitionsReferenced by url(#id)
ClipPath / MaskCut shapes out of other shapesAvatars, progress arcs

Importing .svg files directly

Hand-transcribing every icon into JSX gets old at about icon four. The transformer compiles .svg files into components at bundle time:

npm install --save-dev react-native-svg-transformer
// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');

const config = getDefaultConfig(__dirname);

config.transformer.babelTransformerPath = require.resolve('react-native-svg-transformer');
// svg must move OUT of assetExts and INTO sourceExts — it is compiled, not copied
config.resolver.assetExts = config.resolver.assetExts.filter((ext) => ext !== 'svg');
config.resolver.sourceExts = [...config.resolver.sourceExts, 'svg'];

module.exports = config;

TypeScript needs to be told what an .svg import is, or it rejects the line before Metro ever sees it:

// declarations.d.ts  (include it in tsconfig)
declare module '*.svg' {
  import type React from 'react';
  import type { SvgProps } from 'react-native-svg';
  const content: React.FC<SvgProps>;
  export default content;
}
import Logo from '../assets/logo.svg';

<Logo width={120} height={32} color="#fb923c" />

Then run npx expo start --clear. Metro caches how it resolved every extension, so without clearing it will keep serving .svg through the old asset pipeline and you will conclude the config did not work. This is the single most common reason people give up on the transformer.

Recolouring icons with one prop

An icon with fill="#000000" baked into every path is a new file for every colour. Replace the hardcoded value with currentColor, which react-native-svg resolves from the color prop on the root:

<!-- assets/heart.svg -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  <path fill="currentColor" d="M12 21s-8-4.9-8-10.3A4.7 4.7 0 0 1 12 7a4.7 4.7 0 0 1 8 3.7C20 16.1 12 21 12 21z"/>
</svg>
import Heart from '../assets/heart.svg';

// one file, every state
<Heart width={24} height={24} color={liked ? '#fb923c' : 'rgba(255,255,255,0.35)'} />

The same substitution is what makes an icon set theme-aware for free: pass the colour from your theme context and every icon follows light and dark mode without a second asset. For gradients, define the paint once in Defs and reference it by id:

import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';

<Svg width="100%" height={120} viewBox="0 0 100 40" preserveAspectRatio="none">
  <Defs>
    <LinearGradient id="warm" x1="0" y1="0" x2="1" y2="0">
      <Stop offset="0" stopColor="#fb923c" stopOpacity="1" />
      <Stop offset="1" stopColor="#f43f5e" stopOpacity="1" />
    </LinearGradient>
  </Defs>
  <Rect x="0" y="0" width="100" height="40" fill="url(#warm)" rx="4" />
</Svg>

Four reasons an SVG renders blank

  1. The file styles itself with CSS. Figma and Illustrator happily export <style>.cls-1{fill:#000}</style> or style="fill:#000". react-native-svg implements SVG presentation attributes, not a CSS engine, so those rules are dropped and the shapes render with default paint. Re-export with presentation attributes, or run the file through SVGOMG with prefer presentation attributes turned on.
  2. No dimensions. A root Svg with no width and height lays out at zero in flexbox. It is not clipped or hidden — it genuinely occupies no space. Always set both, or a flex: 1 parent with explicit bounds.
  3. Unsupported elements. <filter>, <foreignObject>, and animated <animate> tags are either partially supported or ignored. Drop shadows in particular need to be a React Native shadow on a wrapping View, not an SVG filter.
  4. Hundreds of paths. Every element is a real view, so a detailed illustration can be a thousand of them. That is a genuine scroll cost in a list. If an SVG has more than a few dozen paths and never needs to recolour or scale past 3x, export it as a PNG — the performance guide covers the wider view-count problem.

What most apps actually need

In practice most apps touch react-native-svg in three places: an icon set, one or two illustrations on empty states and onboarding, and whatever their charting library renders. If that is you, install the package, add the transformer, sanitise your exports, and you are done — the deeper API surface is for when you need custom drawing.

If you would rather start from a working screen than from an install command, describe it — “an empty state with an illustration, a headline, and a button” — and ShipNative generates it as real React Native, running on your phone, with the SVG plumbing already wired up. Export the project whenever you want to take it further by hand.

Frequently Asked Questions

How do I use SVG in React Native?

Install react-native-svg with expo install, then build the image out of its components — Svg as the root with a viewBox, and Path, Circle, Rect, or G inside it. React Native has no DOM, so an <img src="icon.svg"> equivalent does not exist; the SVG is rendered as real native views described by React components.

Can I import an .svg file directly in React Native?

Only after adding react-native-svg-transformer to your Metro config. It compiles .svg files into React components at bundle time so you can write import Logo from "./logo.svg" and render <Logo width={32} height={32} />. Without it, Metro treats .svg as a static asset and you get a broken image rather than an error.

Why does my SVG render blank in React Native?

Three usual causes. The Svg element has no width and height, so it lays out at zero. The viewBox is missing, so the paths are drawn outside the visible box. Or the file styles its shapes with a CSS <style> block or a style="" attribute — react-native-svg implements SVG attributes, not CSS, so those fills are ignored and everything renders black or invisible. Run the file through SVGOMG with prefer-presentation-attributes enabled.

How do I change the colour of an SVG icon?

Replace the hardcoded fill in the path with fill="currentColor" and pass a color prop to the component — react-native-svg resolves currentColor from the color prop on the root Svg. If you use react-native-svg-transformer, the generated component forwards props to the root, so <Logo color="#fb923c" /> works directly.

Does react-native-svg work in Expo Go?

Yes. react-native-svg is bundled into the Expo Go runtime, which is why so many chart and icon libraries pick it as their renderer — it works without a development build. Always install it with expo install rather than npm so the version matches your SDK.

Is SVG or PNG better for icons in React Native?

SVG for anything geometric or single-colour: one file scales to every density, recolours at runtime, and animates. PNG for photographic or richly detailed artwork, where an SVG would carry hundreds of paths and cost more to render than a bitmap. In practice: icons and illustrations SVG, product imagery PNG or WebP.

→

React Native Charts

Most charting libraries are react-native-svg with a nicer API on top.

Read guide →
→

React Native Progress Bar

The circular variant is an SVG stroke trick — here is the full component.

Read guide →

Ship a real React Native app today

Describe, preview, and export Expo code — free to start.

Build with ShipNative →
ShipNative logoShipnative

Build mobile apps with AI. Describe, preview, and ship to iOS & Android in minutes.

Features

Text to App AIApp Generator from ScreenshotPRD to Mobile App

Tools

All free toolsApp Cost CalculatorApp Name GeneratorApp Store Keyword ToolReact Native Components

Blog

All blog postsHow to Build an App Without CodingBest AI Tools for Real Mobile AppsExpo EAS App Store ChecklistLovable, Cursor & v0 for MobileBest AI App Builders in 2026React Native AI App Builder Guide

Legal

FAQTerms of ServicePrivacy Policy

© 2026 ShipNative. All rights reserved.