Working with icons in React Native can be a pain — especially if you want to use SVGs instead of PNGs. Luckily, there’s a clean way to make it all work seamlessly with react-native-svg-transformer.
In this article, I’ll show you how to set it up, make it work with TypeScript and Jest, and even add custom props for your SVGs like fill or stroke.
💡 Step 1 — Install the Transformer
First things first, let’s add the dependency that will allow Metro to transform .svg files into React components:
yarn add react-native-svg-transformeror, if you prefer npm:
npm install react-native-svg-transformerThat’s it. The real magic starts in the config.
⚙️ Step 2 — Update Your metro.config.js
We need to tell Metro how to handle .svg files instead of treating them like regular assets.
Here’s the full config that works perfectly with Expo or plain React Native:
const { getDefaultConfig } = require("expo/metro-config")
module.exports = (() => { const config = getDefaultConfig(__dirname) const { transformer, resolver } = config
config.transformer = { ...transformer, getTransformOptions: async () => ({ transform: { inlineRequires: true, }, }), // 👇 The magic line babelTransformerPath: require.resolve("react-native-svg-transformer/expo"), }
config.resolver = { ...resolver, // Remove `.svg` from asset extensions assetExts: resolver.assetExts.filter((ext) => ext !== "svg"), // Add `.svg` to source extensions sourceExts: [...resolver.sourceExts, "cjs", "svg"], }
return config})()Now Metro will know how to parse .svg files as React components.
🧩 Step 3 — Add TypeScript Declarations
If you’re using TypeScript, it’ll complain about importing SVGs unless you tell it what to expect.
Create a declarations.d.ts file in your root directory and add:
declare module "*.svg" { import React from "react" import { SvgProps } from "react-native-svg" const content: React.FC<SvgProps> export default content}Now, TypeScript knows that .svg files are valid React components that accept SvgProps.
🧪 Step 4 — Set Up Jest (Optional but Handy)
If you’re testing your components with Jest, you’ll need a mock for .svg imports.
In your jest.config.ts, add:
transformer: { // your existing config},moduleNameMapper: { "\\.svg": "<rootDir>/__mocks__/svgMock.js",},Then, create a simple mock file in __mocks__/svgMock.js:
module.exports = "SvgMock"module.exports.ReactComponent = "SvgMock"Now your tests won’t break when SVGs are imported.
🧠 Step 5 — Try It Out
Let’s add a test icon called menu.svg
Create a new file called svg.ts to export it easily:
import MenuSVG from "assets/svgs/menu.svg"export { MenuSVG }Now you can import it anywhere:
import { MenuSVG } from "path/to/svg"
<MenuSVG width={24} height={24} />Clean and simple.
🎨 Step 6 — Add Custom Props to Your SVGs
Want to dynamically change your SVG colors? Easy.
Create a .svgrrc file at the root of your project and add:
{ "replaceAttrValues": { "#000": "{props.fill}" }}This lets you override the hardcoded fill color in the SVG.
Now you can do this:
<MenuSVG fill={colors.palette.neutral100} />Boom 💥 — fully dynamic icons.
✅ Conclusion
That’s it! You’ve just set up full SVG support in your React Native app — with Metro, TypeScript, Jest, and prop customization. No more converting icons or struggling with weird configs.
SVGs now behave like first-class React components — reusable, customizable, and perfect for a scalable design system.