How to create custom wavy headers with react-native-svg

Published on May 26, 2020

8 min read

EXPO

Originally Published at Heartbeat.Fritz.ai

In React Native apps, the support for SVG graphics is provided by an open-source module called react-native-svg that is maintained by React Native community.

Using SVG can enhance an app’s design when it comes to displaying different patterns. It can make a difference in how the look and feel of the app might appear to the end-user, as well how it is easy to edit the pattern built using SVG. SVG is mainly found on the web, and while they have similar uses to JPEG, PNG, and WebP image types, SVG is not resolution-dependent. Hence, the definition according to Wikipedia:

Scalable Vector Graphics (SVG) is an Extensible Markup Language (XML)-based vector image format for two-dimensional graphics with support for interactivity and animation.

This format consists of shapes rather than pixels which can further be concluded that an SVG graphic can be scaled indefinitely in terms of resolution.

In this post, let us learn how to use react-native-svg in React Native and Expo apps and create some custom examples such as wavy header shown below.

Requirements

🔗

Ensure your dev environment includes the following required packages:

  • Node.js above 12.x.x installed on your local machine
  • JavaScript/ES6 basics
  • expo-cli

Installing react-native-svg library

🔗

Start by creating a new project using expo-cli. Navigate inside the project directory when the CLI has finished generating the new project. Then install all the required dependencies to integrate the react-native-svg library.

expo init [PROJECT NAME]
cd [PROJECT NAME]
expo install react-native-svg

The reason to use expo install command when building a React Native app using Expo SDK instead of package managers like npm or yarn is that it is going to install the most compatible version of the package available to be used with Expo SDK. This avoids unnecessary errors.

That's it for installing this library. The react-native-svg library contains common shapes and elements such as Svg, Rect, Circle, Line, Polygon, Path, and so on as components to be used. You are going to see Svg and Path in action, in this post.

Create a header component

🔗

In the next few sections, let us try to create a custom header background that has a bottom border with the form of a wave as shown below.

Start by creating a new screen component inside src/screens/ScreenOne.js file that displays a heading on the screen. (Create the directory if it doesn't exist.)

Add the following code snippet to this file.

1import React from 'react';
2import { StyleSheet, View, Text, Dimensions } from 'react-native';
3
4export default function ScreenOne() {
5 return (
6 <View style={styles.container}>
7 <View style={styles.headerContainer}>
8 <Text style={styles.headerText}>Custom Header</Text>
9 </View>
10 </View>
11 );
12}
13
14const styles = StyleSheet.create({
15 container: {
16 flex: 1,
17 backgroundColor: '#fff'
18 },
19 headerContainer: {
20 marginTop: 50,
21 marginHorizontal: 10
22 },
23 headerText: {
24 fontSize: 30,
25 fontWeight: 'bold',
26 color: '#333',
27 textAlign: 'center',
28 marginTop: 35
29 }
30});

Next, go to App.js file and modify it to render the ScreenOne functional component as below.

1import React from 'react';
2import ScreenOne from './src/screens/ScreenOne';
3import { StatusBar } from 'react-native';
4
5export default function App() {
6 return (
7 <>
8 <StatusBar hidden={true} />
9 <ScreenOne />
10 </>
11 );
12}

Lastly, to see this simple header text on a device's screen, from the terminal window, execute the command expo start. You should results similar to the screenshot below:

Create a custom header component with waves

🔗

The motive of this section is to add a custom header using the svg component in the background in the ScreenOne.js file.

The SVG component that we intend to create is going to wrap the path drawing primitive. This primitive is the outline of a shape that can be filled or stroked. It primitive is represented by the Path component from react-native-svg library and makes use of different commands such as elliptical Arc, moveto, linetoand so on. You can read more about Paths here.

To generate the SVG background as you have seen in the previous section, I am going to make use of getwaves.io. This web tool allows you to generate custom wave patterns in SVG format. Check out their website, it is simple and fulfils the purpose. You can create different patterns using this tool.

Make sure to copy the values of properties such as viewbox and d as shown above.

Next, create a file called WavyHeader.js inside src/components/ directory. Import the following statements.

1import React from 'react';
2import { View } from 'react-native';
3import Svg, { Path } from 'react-native-svg';

Create a functional component called WavyHeader that is going to have a prop passed from the parent (the screen component) it is going to be used. Let us call this prop customStyles. The main reason to pass this prop here is to define the dimensions of the screen component in its own file and keep the style value dynamic for different screens.

Here is the complete code snippet for this custom component. Notice the properties of the Path component are the same as copied from getwaves.io.

1export default function WavyHeader({ customStyles }) {
2 return (
3 <View style={customStyles}>
4 <View style={{ backgroundColor: '#5000ca', height: 160 }}>
5 <Svg
6 height="60%"
7 width="100%"
8 viewBox="0 0 1440 320"
9 style={{ position: 'absolute', top: 130 }}
10 >
11 <Path
12 fill="#5000ca"
13 d="M0,96L48,112C96,128,192,160,288,186.7C384
14 ,213,480,235,576,213.3C672,192,768,128,864,
15 128C960,128,1056,192,1152,208C1248,224,1344,192,
16 1392,176L1440,160L1440,0L1392,0C1344,0,1248,0,
17 1152,0C1056,0,960,0,864,0C768,0,672,0,576,0C480,0,
18 384,0,288,0C192,0,96,0,48,0L0,0Z"
19 />
20 </Svg>
21 </View>
22 </View>
23 );
24}

Now, go back to the ScreenOne.js file and import this custom component after the rest of the import statements.

1// rest of the import statements
2import WavyHeader from '../components/WavyHeader';

Add this component before the <View> that represents headerContainer.

1export default function ScreenOne() {
2 return (
3 <View style={styles.container}>
4 <WavyHeader customStyles={styles.svgCurve} />
5 <View style={styles.headerContainer}>
6 <Text style={styles.headerText}>Custom Header</Text>
7 </View>
8 </View>
9 );
10}

Lastly, define the style reference svgCurve in the StyleSheet object as shown in the snippet below.

1const styles = StyleSheet.create({
2 // rest of the styles
3 svgCurve: {
4 position: 'absolute',
5 width: Dimensions.get('window').width
6 },
7 headerText: {
8 fontSize: 30,
9 fontWeight: 'bold',
10 // change the color property for better output
11 color: '#fff',
12 textAlign: 'center',
13 marginTop: 35
14 }
15});

From the snippet, you can notice that using the Dimensions API from react-native we are going to get the width of the current window. The position property is set to absolute such that the header component that contains the heading is displayed and does not hide behind this wavy background.

The final result is going to be as the following.

Make WavyHeader component reusable

🔗

So far, you have completed the task of displaying the wavy header background on a screen component. But what if the scenario changes and you have two screens both require wavy header backgrounds but with some customization such as each having a different height as well as different wave pattern?

In this section, let us customize the WavyHeader component to accept more props in order to make it a reusable component.

First, let us customize the WavyHeader.js file to accept more props.

1export default function WavyHeader({
2 customStyles,
3 customHeight,
4 customTop,
5 customBgColor,
6 customWavePattern
7}) {
8 return (
9 <View style={customStyles}>
10 <View style={{ backgroundColor: customBgColor, height: customHeight }}>
11 <Svg
12 height="60%"
13 width="100%"
14 viewBox="0 0 1440 320"
15 style={{ position: 'absolute', top: customTop }}
16 >
17 <Path fill={customBgColor} d={customWavePattern} />
18 </Svg>
19 </View>
20 </View>
21 );
22}

Now the <Path /> component is going to accept values (such as backgroundColor, height) in the form of props passed to the WavyHeader component.

Next, go to the ScreenOne.js file and pass in the values for the props for the WavyHeader component.

1export default function ScreenOne() {
2 return (
3 <View style={styles.container}>
4 <WavyHeader
5 customStyles={styles.svgCurve}
6 customHeight={160}
7 customTop={130}
8 customBgColor="#5000ca"
9 customWavePattern="M0,96L48,112C96,128,192,160,288,
10 186.7C384,213,480,235,576,213.3C672,192,768,128,864,
11 128C960,128,1056,192,1152,208C1248,224,1344,192,1392,
12 176L1440,160L1440,0L1392,0C1344,0,1248,0,1152,0C1056,
13 0,960,0,864,0C768,0,672,0,576,0C480,0,384,0,288,0C192,
14 0,96,0,48,0L0,0Z"
15 />
16 <View style={styles.headerContainer}>
17 <Text style={styles.headerText}>Custom Header</Text>
18 </View>
19 </View>
20 );
21}

You won’t see a difference in the result on the device’s screen unless you change the values of these props.

Conclusion

🔗

You can try adding more custom screens to have different wave patterns and try to use the WavyHeader component as reusable for different screens. Here is an example below that displays two different screens with different wave patterns as well as background color and height.

Here is the list of resources used in order to create this post:


More Posts

Browse all posts

Aman Mittal author

I'm a software developer and a technical writer. On this blog, I write about my learnings in software development and technical writing.

Currently, working maintaining docs at 𝝠 Expo. Read more about me on the About page.


Copyright ©  2019-2024 Aman Mittal · All Rights Reserved.