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