How to Use SVG Icons in React Native & Expo (2026 Guide)
The Executive Summary for Mobile Engineers: Web SVG code cannot be pasted into React Native without bridging through native modules. To achieve 60 FPS vector icons in production:
- Core Native Bridge: Install
react-native-svg— fully optimized for React Native's New Architecture (Fabric) and Expo SDK 51/52. - Direct Asset Imports: Configure
react-native-svg-transformerinmetro.config.jsto import.svgfiles directly into JSX trees. - Production Component Pipelines: Use
@svgr/cli --nativeto compile batch vector icons into typed, standalone.tsxcomponents with dynamic color props. - List Performance: Memoize icon components with
React.memowhen rendering large lists insideFlashListorFlatListto avoid repeated native bridge recalculations.
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
UIViewand Core Graphics layer hierarchies. - On Android, components render to
android.view.Viewand nativeCanvasdrawing 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 ..
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.