Back

Working with SVGs in React Native

Working with SVGs in React Native

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 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

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

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 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, 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.

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.

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

Converting an existing SVG image to a React Native component can be a chore. Luckily, an open-source tool called SVGR Playground lets you generate a React Native component from an SVG.

SVGR Playground

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 is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.

replayer.png

Start enjoying your debugging experience - start using OpenReplay for free.

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

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.

// 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

Another way of achieving this is by using another library called 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.

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.

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. 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.

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

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

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 to create the animations.

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. 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.