Mobile Architecture

How to Use SVG Icons in React Native & Expo (2026 Guide)

1. Why Standard Web <svg> Fails in React Native

Every web developer transitioning to React Native encounters this runtime crash when copying an SVG directly from the web:

Invariant Violation: View config not found for name svg.
Make sure to start component names with a capital letter!

Web browsers possess native HTML/XML parsers that directly parse <svg>, <path>, and <defs> into a DOM tree styled by CSS. In contrast, React Native maps your JSX components through the Yoga flexbox layout engine into platform-native UI widgets:

  • On iOS, components render to UIView and Core Graphics layer hierarchies.
  • On Android, components render to android.view.View and native Canvas drawing routines.

Neither iOS nor Android has a native <svg> element. To render resolution-independent vectors on mobile screens without pixelation on 3x Retina displays or 440 DPI Android devices, you must use react-native-svg, which bridges vector mathematical paths directly to Core Graphics and Skia/Android Canvas.

2. Installation & Setup (Expo vs Bare React Native)

In 2026, react-native-svg is the undisputed standard native module for mobile vectors. It fully supports React Native's New Architecture (Fabric C++ renderer and TurboModules).

Expo Managed Workflow (SDK 50, 51 & 52)

Expo provides automated native dependency matching. Run the following command inside your project root:

npx expo install react-native-svg

Because react-native-svg is included in the Expo Go client, it works immediately during development without requiring custom development builds (EAS Prebuild).

Bare React Native (CLI Workflow)

For standalone React Native applications, install the package and install iOS CocoaPods:

# 1. Install npm package
npm install react-native-svg

# 2. Link iOS native pods (CocoaPods)
cd ios && pod install && cd ..
New Architecture (Fabric) Note

If your app targets React Native 0.74+ with newArchEnabled=true, react-native-svg automatically activates its Fabric C++ native components, eliminating asynchronous bridge serializations for smoother 120 Hz screen scrolls.

3. Approach 1: Pre-Compiled TypeScript Icon Components (Recommended)

For production design systems, converting SVG files into pre-compiled TypeScript components via SVGR CLI offers the best performance, instant tree-shaking, and zero Metro runtime bundle overhead.

The SVGR CLI Native Command

You can convert any raw SVG icon from IconStash into a clean React Native component using the --native flag:

npx @svgr/cli --native --icon --typescript \
  --replace-attr-values "#000={props.color || '#F2F2F2'}" \
  --out-dir src/components/icons \
  raw-icons/

Production Typed Component Pattern

Here is what an optimal, production-grade icon component looks like in React Native with TypeScript:

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

export interface IconProps extends SvgProps {
  size?: number;
  color?: string;
}

export const SearchIcon = memo(({
  size = 24,
  color = '#F2F2F2',
  strokeWidth = 2,
  ...props
}: IconProps) => {
  return (
    <Svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      stroke={color}
      strokeWidth={strokeWidth}
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <Path d="m21 21-4.35-4.35" />
      <Path d="M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z" />
    </Svg>
  );
});

SearchIcon.displayName = 'SearchIcon';

4. Approach 2: Direct .svg Imports with Metro Transformer

If your team prefers keeping raw .svg files in your repository and importing them like web modules (import BellIcon from './assets/bell.svg'), configure react-native-svg-transformer.

Step 1: Install the Transformer

npm install --save-dev react-native-svg-transformer

Step 2: Configure metro.config.js

For Expo SDK 50+, update metro.config.js using the Expo Metro configuration helper:

const { getDefaultConfig } = require('expo/metro-config');

module.exports = (() => {
  const config = getDefaultConfig(__dirname);
  const { transformer, resolver } = config;

  config.transformer = {
    ...transformer,
    babelTransformerPath: require.resolve('react-native-svg-transformer'),
  };
  config.resolver = {
    ...resolver,
    assetExts: resolver.assetExts.filter((ext) => ext !== 'svg'),
    sourceExts: [...resolver.sourceExts, 'svg'],
  };

  return config;
})();

Step 3: Add TypeScript Declarations

To avoid TypeScript reporting Cannot find module './bell.svg', create a declarations.d.ts file in your project root:

declare module '*.svg' {
  import React from 'react';
  import { SvgProps } from 'react-native-svg';
  const content: React.FC<SvgProps>;
  export default content;
}

Step 4: Using Direct SVG Imports in Screens

import React from 'react';
import { View, StyleSheet } from 'react-native';
import BellIcon from '../assets/icons/bell.svg';

export function NotificationBadge() {
  return (
    <View style={styles.container}>
      <BellIcon width={24} height={24} stroke="#C1DD2D" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 12, alignItems: 'center' },
});

5. Dynamic Color Theming & Dark Mode in React Native

On the web, CSS provides the miraculous currentColor keyword, causing SVG icons to inherit font colors automatically. React Native does not support CSS currentColor.

If you pass stroke="currentColor" on iOS or Android, the native renderer falls back to opaque black (#000000), breaking dark mode interfaces.

Solution 1: Prop Forwarding with useColorScheme()

import React from 'react';
import { useColorScheme } from 'react-native';
import { SearchIcon } from './icons/SearchIcon';

export function ThemedSearchBar() {
  const colorScheme = useColorScheme();
  const iconColor = colorScheme === 'dark' ? '#C1DD2D' : '#1A1A1A';

  return <SearchIcon size={20} color={iconColor} />;
}

Solution 2: Creating a Universal Design Token Wrapper

Wrap your icon components with your design system's color tokens to ensure brand consistency:

import React from 'react';
import { useTheme } from '../theme/ThemeProvider';
import { IconProps } from './types';

export function createThemedIcon(IconComponent: React.ComponentType<IconProps>) {
  return function ThemedIcon({ color, ...props }: IconProps) {
    const { colors } = useTheme();
    const resolvedColor = color || colors.iconDefault;
    return <IconComponent color={resolvedColor} {...props} />;
  };
}

6. Comparison: react-native-svg vs @expo/vector-icons vs Bitmaps

Before standardizing your mobile iconography, consider the trade-offs across bundle size, flexibility, and runtime memory:

Architecture Bundle Impact Multi-Color / Duotone Tree-Shaking FOUC / FOIT Risk Render Speed
Pre-compiled react-native-svg (TSX) ~0.8 KB per icon (Minimal) 100% Full Support Flawless (Per-component) None (Zero font load) 60 FPS (CoreGraphics / Skia)
Metro SVG Transformer ~1.2 KB per icon 100% Full Support Good (File-level) None 60 FPS
@expo/vector-icons (Icon Fonts) ~1.4 MB to 4 MB (All TTF Glyphs) Single color only Poor (Ships entire TTF file) Possible font delay flash Fast (Native glyph text)
PNG Bitmaps (@1x, @2x, @3x) ~45 KB per icon (All scales) Fixed colors only Manual asset stripping None Very fast (Pre-rasterized)

Verdict: For modern React Native and Expo apps, pre-compiled TSX components using react-native-svg deliver the leanest app bundles, full multi-color and gradient support, and zero font-flash glitches.

7. High-Performance Optimization in FlatList & FlashList

When displaying feeds, contacts, or tables containing hundreds of rows with icons, unoptimized SVGs can cause bridge bottlenecks and frame drops. Apply these 3 mobile performance rules:

1. Wrap Icons with React.memo & Provide Explicit Stroke Props

Prevent re-evaluating SVG path strings during scroll events when row state changes, and declare explicit stroke and fill rules:

import React, { memo } from 'react';
import Svg, { Path, Circle } from 'react-native-svg';
import { IconProps } from './SearchIcon';

export const ProfileIcon = memo(({
  size = 24,
  color = '#F2F2F2',
  strokeWidth = 2,
  ...props
}: IconProps) => {
  return (
    <Svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      stroke={color}
      strokeWidth={strokeWidth}
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <Path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
      <Circle cx="12" cy="7" r="4" />
    </Svg>
  );
});

ProfileIcon.displayName = 'ProfileIcon';

Critical Mobile Rule: Because react-native-svg defaults fill to black (#000000) and React Native does not support CSS currentColor, always pass explicit fill="none" and stroke={color} props. Omitting these causes vector outline paths to fill as deformed solid black polygons.

2. Avoid Dynamic String Concatenation Inside Paths

Do not calculate complex Bézier curve strings inside component render cycles. Keep path strings static or compile them at build time.

3. Eliminate Unused Precision with SVGO

Icons exported with 5 decimal places (d="M12.48392 3.19483...") consume unnecessary memory and JSON serialization time across the native bridge. Strip precision down to 2 decimal places before importing into React Native.

Frequently Asked Questions

Why can't React Native render standard web <svg> tags natively?

React Native does not use a browser DOM or CSS engine. Its layout engine (Yoga) maps JSX nodes to native iOS (UIView/CoreGraphics) and Android (View/Canvas) primitives. Web <svg>, <path>, and <circle> elements have no native counterparts unless bridged through the react-native-svg native module.

What is the best way to use SVG icons in Expo SDK 51 and 52?

The recommended approach in Expo is installing react-native-svg via 'npx expo install react-native-svg' and configuring react-native-svg-transformer in metro.config.js for direct .svg imports, or using @svgr/cli with the --native flag to generate pre-compiled TypeScript components for maximum runtime performance.

How do you handle currentColor and dynamic theming in React Native SVG icons?

React Native does not support CSS cascade inheritance or the web 'currentColor' keyword natively. To theme icons dynamically, replace hardcoded fills/strokes in your SVGR config with props or pass a 'color' prop through React props or useColorScheme() into stroke={color} or fill={color}.

Is react-native-svg faster than @expo/vector-icons icon fonts?

Pre-compiled react-native-svg components offer superior tree-shaking (shipping only the exact paths you render), zero font-loading FOIT/FOUC, and full multi-color/duotone fidelity. Icon fonts carry full TTF binary bundle weight and lack multi-color support, though font glyphs can render marginally faster in very long unmemoized lists.

Supercharge Your React Native Icon Workflow

Search 134,701 open-source vector icons across 28 curated libraries on IconStash. Clean SVG code ready for instant mobile export.

Search All 134K+ Icons →