Working with SVGs in React Native
Tags: javascript, webdev, reactnative, svg
Published: 2022-04-26 15:04:28

by [Samaila Bala](https://blog.openreplay.com/authors/samaila-bala)

Scalable Vector Graphic (SVG) is an image format that uses vector graphics to display the image you see. They are now popular among developers because they scale to any resolution. Other advantages of SVGs include:

- **Easily Editable:** SVG files can be created and edited with any text editor. You can also manipulate the properties with CSS.
- **Small File Size:** due to the nature of SVGs, the resolutions don't affect the file sizes allowing the file sizes to be minimal when compared to the pixel-based counterparts
- **SEO Friendly:** because of its XML markup language format SVG is SEO friendly as you can add keywords and descriptions to the image directly.
- **They can be animated:** We said that customizing and editing SVG files is easy. We can then animate them with CSS and JavaScript

In this article, we will be looking at different ways of manipulating SVG images in React Native applications.

## Setting up a React Native Project

We will be using the Expo framework to bootstrap our React Native application. Make sure you have [Node.js/npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)  on your machine. Open a terminal and run the code below to install `expo-cli` globally.

```
npm install -global expo-cli
```

After installation, run the code below to create a new react-native project

```
expo install react-native-svg-tutorial
```

This command will launch an interactive prompt for you to select a template. Choose blank and press the enter/return key to continue the installation.

![Expo installation interactive prompt](https://blog.openreplay.com/static/917a35180c823e0d28e3c5a63f7199b3/b80c1/image01.jpg)


Once the process is complete, navigate to the root of the project directory and run the code below to start the expo development server.

```
expo start react-native-svg-tutorial
```

You will be presented with an interactive menu similar to the screenshot below.

![Expo development server interactive menu](https://blog.openreplay.com/static/904d62304230cabe9c1ff0417a8f2f33/b2ee5/image02.jpg)

The Expo dev server allows you to test your application locally while in development. You will need an emulator or the Expo Go App to run the app. (Note: the installation of an emulator isn't covered in this article.) Nevertheless, you can check [how to install an emulator [this article](https://docs.expo.dev/get-started/installation/) to install the required tools. 

Assuming you have an emulator installed, press the relevant key that applies to the emulator, and it'll run the app on the emulator.

## Creating SVG in React Native

We will be creating a custom loader for an application. To start, we will need [react-native-svg](https://www.npmjs.com/package/react-native-svg), a library that provides SVG support for react-native applications. Open a terminal and navigate to the root of your project. Run the code below to install the library

```
expo install react-native-svg
```

After installing, create a file called `Loader.js` in the root directory and paste the code below into the file.

```javascript
import * as React from "react";
import Svg, { Path } from "react-native-svg";
const Loader = (props) => (
  <Svg
    width={118}
    height={107}
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    {...props}
  >
    <Path
      d="M32.333 6C17.608 6 5.667 17.819 5.667 32.4c0 11.77 4.666 39.707 50.602 67.947a5.26 5.26 0 0 0 5.462 0c45.936-28.24 50.602-56.176 50.602-67.947 0-14.581-11.941-26.4-26.666-26.4C70.94 6 59 22 59 22S47.059 6 32.333 6Z"
      stroke="#F24E1E"
      strokeWidth={10.667}
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </Svg>
);
export default Loader;
```

If you've used SVG images on the web, this should look familiar. The major difference here is that we are using the components provided by `react-native-svg` to create our SVG image instead of using HTML elements. The `react-native-svg`  components use sentence case in naming to differentiate from the HTML elements, which are lower case. To render our SVG go to the `App.js` file and modify it to look like the code below.

```javascript
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View } from "react-native";
import Loader from "./Loader";

export default function App() {
  return (
    <View style={styles.container}>
      <Loader />
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});
```

Save, and reload your emulator; you should be presented with a screenshot similar to the screenshot below.


![SVG loader example](https://blog.openreplay.com/static/0df920f66197f0a2624c55731bd803a3/c6aee/image03.png)


Converting an existing SVG image to a React Native component can be a chore. Luckily, an open-source tool called [SVGR Playground](https://react-svgr.com/playground/?native=true) lets you generate a React Native component from an SVG. 


![SVGR Playground](https://blog.openreplay.com/static/4ecd25e10eabb921dd5c26f37469685c/1a152/image04.png)


It lets you paste an SVG image on the left and generates a React Native SVG component on the right to copy and use. You can play with it to see how it works.


## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647097041609/Qi6sMOaaB.png)

_Happy debugging for modern frontend teams - [start monitoring your web app for free](https://github.com/openreplay/openreplay)._



## Adding External SVG to React Native applications

The advantage of creating a React Native SVG component is that it is customizable. We can pass props and animate, as we will see in the next section, but there are times when we just want to use an external SVG image without customizing it.  

There are two ways to achieve this. The `react-native-svg` library has a `SvgUri` component that allows us to create SVG components from external sources. Create a file called `SvgExternal.js` and paste the code below

```javascript
import * as React from "react";
import { SvgUri } from "react-native-svg";

const SvgExternal = (props) => (
  <SvgUri
    width={118}
    height={107}
    uri="https://placeholder.pics/svg/118x107/DEDEDE/555555/SVG"
    {...props}
  />
);
export default SvgExternal;
```

It provides a `uri` prop that we can pass a link to an external site. Go to the `App.js` file and modify the code to display the external SVG.

```javascript
// previous code

import SvgExternal from "./SvgExternal";
export default function App() {
  return (
    <View style={styles.container}>
      <SvgExternal />
      <StatusBar style="auto" />
    </View>
  );
}

// previous code
```

Now you can open your emulator to view the changes.

![Viewing changes in the emulator](https://blog.openreplay.com/static/f6efc492559f5cca08248bd12e6720d4/c6aee/image05.png)

Another way of achieving this is by using another library called [react-native-svg-transformer](https://www.npmjs.com/package/react-native-svg-transformer). It lets you import SVG files into React Native projects. Run the code below in your projects terminal to install the library

```
yarn add --dev react-native-svg-transformer
```

Create a file called `metro.config.js` in your project's root and paste the code below into it.

```javascript
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;
})();
```

The `metro.config.js` is a config file for Metro, a JavaScript bundler for React Native. If you created a react-native project without Expo, paste the code below in your  `metro.config.js` as the configurations for Expo are different from a bare React Native app.

```javascript
const { getDefaultConfig } = require("metro-config");

module.exports = (async () => {
  const {
    resolver: { sourceExts, assetExts },
  } = await getDefaultConfig();
  return {
    transformer: {
      babelTransformerPath: require.resolve(
        "react-native-svg-transformer"
      ),
    },
    resolver: {
      assetExts: assetExts.filter((ext) => ext !== "svg"),
      sourceExts: [...sourceExts, "svg"],
    },
  };
})();
```

The next step is getting an SVG file. You can download any on the internet or use [this](https://drive.google.com/file/d/1aYTJDHoVx69SBFg8B1nKQUhhgKA-540x/view?usp=sharing). Move the downloaded file to the `assets` directory in your project. Now go to the `App.js` file and modify it like the code below to use the file you've downloaded.

```javascript
import { StatusBar } from "expo-status-bar";
import { StyleSheet, View } from "react-native";
import PurpleHeart from "./assets/purple-heart.svg";
export default function App() {
  return (
    <View style={styles.container}>
      <PurpleHeart />
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});
```

Save when you're done, and view the results in your emulator.


![External SVG image](https://blog.openreplay.com/static/594c77d0d1c877d5a50a1562672072f4/c6aee/image06.png)



## Animating SVGs in React Native

We've so far looked at different ways of adding Svg to react-native. In this section, we will look at how to animate SVG in react-native. We plan to achieve the screenshot below.

![Animated SVG](https://blog.openreplay.com/624a88dd8f06999d7ef3f451928be905/image07.gif)

What we want to do is to change the stroke color of the SVG component every few milliseconds. To get started, create a file called `AnimatedLoader.js` and paste the code below. We will be using the React Native [Animated API](https://reactnative.dev/docs/animations) to create the animations.

```javascript
import React, { useEffect, useRef } from "react";
import { Animated } from "react-native";
import Svg, { Path } from "react-native-svg";

const AnimatedPath = Animated.createAnimatedComponent(Path);
const AnimatedLoader = (props) => {
  const color = useRef(new Animated.Value(0)).current;
  useEffect(() => {
    Animated.loop(
      Animated.sequence([
        Animated.timing(color, {
          duration: 1000,
          toValue: 1,
          useNativeDriver: true,
        }),
        Animated.timing(color, {
          duration: 1000,
          toValue: 0,
          useNativeDriver: true,
        }),
      ])
    ).start();
  }, []);

  return (
    <Svg
      width={118}
      height={107}
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <AnimatedPath
        d="M32.333 6C17.608 6 5.667 17.819 5.667 32.4c0 11.77 4.666 39.707 50.602 67.947a5.26 5.26 0 0 0 5.462 0c45.936-28.24 50.602-56.176 50.602-67.947 0-14.581-11.941-26.4-26.666-26.4C70.94 6 59 22 59 22S47.059 6 32.333 6Z"
        stroke={color.interpolate({
          inputRange: [0, 0.2, 0.4, 0.8, 1],
          outputRange: [
            "rgb(147, 189, 186)",
            "rgb(235, 154, 64)",
            "rgb(226, 117, 58)",
            "rgb(220, 85, 52)",
            "rgb(220, 85, 52)",
          ],
        })}
        strokeWidth={10.667}
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </Svg>
  );
};

export default AnimatedLoader;
```

 The first thing we've done here is to make the `Path` component animable, allowing us to apply animations to the `Path` component.


    const AnimatedPath = Animated.createAnimatedComponent(Path);

The next step is creating an `Animated.Value` that we can attach to an animated component. We used a `useRef` hook to store the `Animated.Value` so we don't get to mutate it directly. We've created our animation in the `useEffect` hook: a loop that creates a fade-in and fade-out effect.

The last thing to do is hook up the animation with the component that needs it. In this case, the `AnimatedPath`. We've attached the `color`  `Animated.Value` to the `stroke` prop of the `AnimatedPath` to interpolate the `color` Animated Value, creating a color mapping between the `inputRange` and `outputRange`. Save and reload your emulator to view the changes.


## Conclusion

We've covered how to use and animate SVG's in React Native. When it comes to animating, there is much more, going beyond the scope of this article. Endeavor to check the React Native [Animated API](https://reactnative.dev/docs/animations). Animating SVG in React Native has some performance drawbacks, especially for complex animations, so endeavor to keep it simple. The code of this article is available [here](https://github.com/sa-ma/react-native-svg-tutorial).