If you’re a beginner to React Native you may feel that styling React Native applications can be challenging and different from what you’re used to. The UI design is an essential part of any application and it is therefore essential to learn how to create a nice and responsive UI for React Native applications.

Luckily for us, Material UI is a library consisting of a large set of pre-designed components using the Material design system developed by Google back in 2014. Material UI was mainly created for React and web development, but I’ll show you how to Material UI components in a React Native application.

papers

There are several libraries which offer support for Material UI components in React Native. We’ll be using Paper which is one of the most popular libraries with over 35,000 weekly downloads and over 7,000 stars on GitHub. Paper is a collection of customizable and production-ready components for both iOS and Android, it follows Google’s Material Design guidelines, offers full theme support and is very simple to use.

Here’s a quick overview of what we’ll cover in this post:

  • Create a new React Native app from scratch
  • Install dependencies to add Material UI designed components
  • Create a custom theme
  • Use the custom theme in components

Before we start, this is a beginners tutorial for building and styling apps with React Native using Material UI components. We will be creating a React Native project from scratch, but the focus will still be on adding Material UI components to a React Native project. If you get stuck of want to find our more information related to React Native, I recommend jumping over to the official React Native documentation.

The complete source code for the project we’ll be developing is available on GitHub here.

Let’s begin!

Create a new React Native project

We’ll be building a React Native app using Expo, which is the easiest way for beginners to get started.

To do so, you need to install the Expo CLI if you don’t have it installed already. Install it globally with the following command:

npm install -g expo-cli

Then we’ll create a new React App. When running the below command, you’ll be prompted to choose a template. Choose blank: a minimal app as clean as an empty canvas.

expo init AwesomeProject

The we can run the React Native app to see that it works.

cd AwesomeProject
npm start

This will start a development server and opens localhost in your web browser and you can choice what device to run on. Below is an example of running the application using an iOS device.

empty-react-native-project

As you can see, the app is very simple but we’ll soon change that by creating a custom UI for the React Native using Material UI.

Note: If you run into any issues during this step, I recommend jumping over to the official React Native installation guides.

Project setup and configuration

Before we start, I always prefer creating folders to separate the code of the project. A good structure in the early stages of a project, will be help in the development and especially as it grows. This is a good habit to learn as a developer.

Open the project in the editor of your choice. First create a new folder src in which we’ll use as an entry point for the code that we add. Next we add the folder Screens inside the src folder. If you create your own components, I recommend creating a separate folder Components as well.

In the Screens folder we’ll add our different app screens. Your project structure should now look like this:

project-structure-react-native

React Native Material UI using Paper

In order to start using the Material UI components through React Native Paper, we need to install the library. Run the following command in your terminal:

npm install react-native-paper

That is everything that is required to install the library. Now we have access to the large set of pre-built components and can add Material UI styled components in our React Native app.

Adding React Native Paper Components

To get started using Material UI components in React Native, we need to wrap the entire app within a Provider from the package react-native-paper. Inside the App.js file, we’ll import the necessary libraries and components.

When wrapping the application within the PaperProvider component, all the components in the framework will receive the styled theme. We will create our custom theme later, but we’ll use the default styled theme for now.

Open the App.js file within your code editor and replace all the code with the following:

import * as React from "react";
import { AppRegistry } from "react-native";
import { Provider as PaperProvider } from "react-native-paper";
import { name as appName } from "./app.json";
import MainScreen from "./src/Screens/MainScreen";

export default function App() {
  return (
    <PaperProvider>
      <MainScreen />
    </PaperProvider>
  );
}

AppRegistry.registerComponent(appName, () => App);

In the above code we you may notice that we import MainScreen from ./src/Screens/MainScreen. So we’ll need to create that file which will act as the entry point to the application.

Create a new file Mainscreen.js inside the folder src/Screens. Add the following code within the file:

import * as React from "react";
import { SafeAreaView, StyleSheet, Text } from "react-native";
import { Button } from "react-native-paper";

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <Text>My cool React Native App.</Text>
      <Button
        icon="camera"
        mode="contained"
        onPress={() => console.log("Pressed")}
      >
        Press me
      </Button>
    </SafeAreaView>
  );
}

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

The main screen component is very simple. We use a SafeAreaView to render content within the safe area boundaries of the device and a simple Text component. The we also import and use a Button component from the Paper library. That’s how simple it is to use styled Material UI components in a React Native app.

Paper theme customization

As mentioned earlier, the PaperProvider provides the default theme to all the components in the framework. However, one important part of developing a application is to customize colors, fonts etc to make the application unique and align with a companies colors.

We’ll now override the default theme and change the colors and font of the components in the framework. Create a new file Theme.js inside the src folder.

First, we’ll create custom fonts by creating a fontConfig object. It’s possible to specify specific fonts for different platforms by dividing the fontConfig object by platform. The supported platforms are ios, android, macos, windows, web, and native.

Inside the Theme.js file, enter the following code:

const fontConfig = {
  ios: {
    regular: {
      fontFamily: "System",
      fontWeight: "400",
    },
    medium: {
      fontFamily: "System",
      fontWeight: "500",
    },
    light: {
      fontFamily: "System",
      fontWeight: "300",
    },
    thin: {
      fontFamily: "System",
      fontWeight: "100",
    },
  },
  default: {
    regular: {
      fontFamily: "sans-serif",
      fontWeight: "normal",
    },
    medium: {
      fontFamily: "sans-serif-medium",
      fontWeight: "normal",
    },
    light: {
      fontFamily: "sans-serif-light",
      fontWeight: "normal",
    },
    thin: {
      fontFamily: "sans-serif-thin",
      fontWeight: "normal",
    },
  },
};

In the above code we specify platform specific fonts for ios and then provide the default fonts for the other platforms.

The next step is to customize the colors and apply customized fonts to the theme. Inside Theme.js, import the following:

import { configureFonts, DefaultTheme } from "react-native-paper";

Next, paste the following code under the fontConfig object we created earlier.

const theme = {
  ...DefaultTheme,
  fonts: configureFonts(fontConfig),
  colors: {
    ...DefaultTheme.colors,
    primary: "tomato",
    secondary: "blue",
  },
};

export default theme;

So now we applied our custom colors and fonts together with the default styling. But, let’s go through the above code line-by-line to get a better understanding what’s going on.

We create a new theme object and then used an ES6 spread operator to apply the default theme props. This allows use to only override specific parts and use the defaults for the remaining ones. Then we change the fonts the configureFonts(fontConfig) method and passing in the custom font configuration. Finally, we apply the DefaultTheme.colors again using a ES6 spread operator and override the primary and secondary color.

Now we just need to apply our customized theme to the entire application, which is very easy thanks to the PaperProvider component. Back in App.js, we import the src/Theme.js file and pass the theme as a prop to the PaperProvider component.

import theme from "./src/Theme";
export default function App() {
  return (
    <PaperProvider theme={theme}>      <MainScreen />
    </PaperProvider>
  );
}

If you open the app again using npm start, you can see that the color of the button has changed to the red tomato color we specified above as primary color.

Using custom themes in components

We can also use the custom themes inside components to style them individually. There are three different ways to customize components using the theme and we’ll use the button to demonstrate each way. We’ll first look into applying the theme to Paper components and then to custom components.

Applying theme to a Paper component

You can pass the theme prop directly to the component which is merged with theme from the PaperProvider. In the below code we make smoothen the corners of the Button component from react-native-paper.

<Button
  icon="camera"
  mode="contained"
  onPress={() => console.log("Pressed")}
  theme={{ roundness: 10 }}>
  Press me
</Button>

Applying theme to a custom component

To access the theme within components that are not part of the Paper library, such as components from React Native, you can use the withTheme high-order component (HOC) from the react-native-paper library. We need to wrap the entire component using withTheme. To apply this in our code, we’ll apply it to the MainScreen component and then use it to change the Text component from React Native.

import { withTheme } from "react-native-paper";

function App(props) {
  const { colors } = props.theme;  return (
    <SafeAreaView style={styles.container}>
      <Text style={{ color: colors.secondary }}>
        Open up App.js to start working on your app!
      </Text>
    </SafeAreaView>
  );
}

export default withTheme(App);

By wrapping the App component with the withTheme HOC, we can access the theme through the props.theme. Then we can extract the colors.secondary from the theme and style the Text component using it.

It’s also possible to apply the theme to custom components using the useTheme hook. We simply import the hook from the react-native-paper and use it inside the component to extract the colors (or any other theme property you wish to access).

import { useTheme } from "react-native-paper";

function App() {
  const { colors } = useTheme();  return (
    <SafeAreaView style={styles.container}>
      <Text style={{ color: colors.secondary }}>        Open up App.js to start working on your app!
      </Text>
    </SafeAreaView>
  );
}

export default App;

Custom Material UI design

Now we have covered the setup and basics of how to add Material UI to a React Native app using the Paper library. It’s now time for you to apply your new skills and create a cool application using a few components from the Paper package.

Bottom nav bar

We’ll begin by adding a BottomNavigation component from React Native Paper which we’ll use to provide navigation between different top-level screens of the application through a nav bar in the bottom of the screen.

There exists several different ways to add top-level navigation in React Native, such as React Navigation to mention one. It’s possible to integrate the BottomNavigation component with React Navigation for those that are interested, read here. Of course, the advantage of using BottomNavigation from React Native Paper is the built-in Material UI designed of the components.

We’ll add the BottomNavigation component to the MainScreen inside src/Screens folder.

import * as React from "react";
import { BottomNavigation } from "react-native-paper";
import HomeRoute from "./HomeScreen";
import ProfileRoute from "./ProfileScreen";

const MainScreen = () => {
  const [index, setIndex] = React.useState(0);
  const [routes] = React.useState([
    { key: "home", title: "Home", icon: "home" },
    { key: "profile", title: "Profile", icon: "user" },
  ]);

  const renderScene = BottomNavigation.SceneMap({
    home: HomeScreen,
    profile: ProfileRoute,
  });

  return (
    <BottomNavigation
      navigationState={{ index, routes }}
      onIndexChange={setIndex}
      renderScene={renderScene}
    />
  );
};

export default MainScreen;

In the code above, we add the BottomNavigation and pass in 3 props. The navigationState holds the state for the bottom navigation and it should contain an index and routes property. routes is an list of route objects used for rendering the tabs, which we have create above with the required properties. The index property represents the index of the active route in the routes array.

BottomNavigation is a controlled component, which means that the data is handled by the component itself. Thus, we need to update the index via the onIndexChange callback to update the selected tab.

Finally, the renderScene props is a callback which returns a react element to render as the screen for the chosen tab.

I have also created to separate screens: HomeScreen and ProfileScreen inside the Screens folder. We import these and pass the components to the SceneMap function to construct the application navigation.

Both screens are the same but adjusted for the correct names. They look as follows:

import * as React from "react";
import { SafeAreaView, StyleSheet } from "react-native";
import { Title } from "react-native-paper";

const HomeRoute = () => (
  <SafeAreaView style={styles.container}>
    <Title>Home page</Title>
  </SafeAreaView>
);
export default HomeRoute;

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

We have now created a basic application with two simple screens. The React Native app now looks like this.

bottomNavigation-paper-react-native-app

App Bar component

Let’s add a simple navbar in the top of the Home screen which shows the name of the page and includes a button to the right. We’ll use the Appbar component which can be used both in the top and bottom of the screen. It usually contains the screen title, controls like navigation buttons to go back to previous, menu button and more.

import * as React from "react";
import { View, StyleSheet } from "react-native";
import { Appbar } from "react-native-paper";

const HomeRoute = () => (
  <View>
    <Appbar.Header>
      <Appbar.Content title="Home Page" />
      <Appbar.Action
        icon="dots-vertical"
        onPress={() => console.log("handle press")}
      />
    </Appbar.Header>
  </View>
);

export default HomeRoute;

As with everything in Papers, it’s easy to add cool components in React Native using Material UI designs. The Appbar component is much more customizable so check it out at the docs.

The app should now look like this:

appbar-react-native-papers

Using React Native icons

We’ve used icons a few times in this tutorial. Many of the components within Papers use react-native-vector-icons which is large library of icons you can use in the app. Since we’re using Expo it works right out of the box.

We’ve already seen how to use an icon together with a Button. Many components accept an icon prop which is used to display an icon. You can pass any name of an icon found in the MaterialCommunityIcons.

<Button icon="camera">Press me</Button>

You can also import icon components directly from expo. Let’s add an icon to the profile page and assign the primary color from our custom theme. Here we import the FontAwesome icon set.

import { FontAwesome } from "@expo/vector-icons";

const ProfileRoute = props => (
  <SafeAreaView style={styles.container}>
    <FontAwesome name="user" size={50} color={props.theme.colors.primary} />
    <Title>Profile page</Title>
  </SafeAreaView>
);
export default withTheme(ProfileRoute);

The profile page should now look like below.

profile-page-icon

Wrap up

I hope this has helped you understand how to use Material UI components in React Native. We used a few components of the React Native Paper library but there is much more to explore. Using the knowledge you learnt here, you should be ready to create a sleek React Native UI.

The complete source code is available on GitHub here.