Gaurav Singhal Gaurav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, web scraping, Angular, and React.

How to create and style custom buttons in React Native

8 min read 2359

Editor’s note: This post was updated 14 January 2022 to improve the tutorials and include a “modern” button styling example.

React Native is an excellent framework for building native mobile applications. It allows you to build apps that will work on both iOS and Android platforms, but core UI components such as <Button /> will look different on each platform. This is because React Native renders platform-specific UI elements, and as a result, there are limited styling and customization options (the official React Native docs admit as much).

For this and many other reasons, it’s critical to know how to create buttons that look consistent regardless of the operating system. In this guide, we’ll walk you through how to create various types of custom buttons in React Native, including:

  • Using the <TouchableOpacity /> component to build buttons with different background colors, sizes, border styles, and text styles
  • Styling buttons with color gradient patterns
  • Designing modern buttons with vector icons (basic sign-in buttons, including those with Facebook and GitHub options)
  • CSS-styled buttons with CSS-in-JS libraries

Setting up your project

Run the following command to get started.

npx react-native init CustomButtonDemo

Remove all the boilerplate code from the App.js file and add the following.

import React from "react";
import { View, Button, StyleSheet } from "react-native";

const App = () => {
  return (
    <View style={styles.screenContainer}>
      <Button title="Hey there!" />
    </View>
  );
};

const styles = StyleSheet.create({
  screenContainer: {
    flex: 1,
    justifyContent: "center",
    padding: 16
  }
});

export default App;

In the above code block, a core <Button /> component is declared and wrapped inside a container. StyleSheet is an API provided by the React Native framework as an abstraction to CSS stylesheets.

Using <TouchableOpacity /> to create custom button components

Now that you’ve set up the main screen, it’s time to turn your attention to the custom button component.

const AppButton = props => (
    // ...
)

Name the custom button component AppButton.

Import the <TouchableOpacity /> and <Text /> components from react-native.

import { View, Button, StyleSheet, TouchableOpacity, Text } from "react-native";

To create custom buttons, you need to customize the <TouchableOpacity /> component and include the <Text /> component inside of it to display the button text.

We made a custom demo for .
No really. Click here to check it out.

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity onPress={onPress} style={styles.appButtonContainer}>
    <Text style={styles.appButtonText}>{title}</Text>
  </TouchableOpacity>
);

Next, create the StyleSheet properties to style the button.

const styles = StyleSheet.create({
  // ...
  appButtonContainer: {
    elevation: 8,
    backgroundColor: "#009688",
    borderRadius: 10,
    paddingVertical: 10,
    paddingHorizontal: 12
  },
  appButtonText: {
    fontSize: 18,
    color: "#fff",
    fontWeight: "bold",
    alignSelf: "center",
    textTransform: "uppercase"
  }
});

The custom button should now look like this:

Our first custom button display

<TouchableOpacity />, as the name suggests, is a touchable component, which means it can respond to the user’s touch. When you press the button, the opacity decreases. You can control the opacity by passing an activeOpacity prop to the <TouchableOpacity /> component.

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity
    activeOpacity={0.8}
    onPress={onPress}
    style={styles.appButtonContainer}
  >
    <Text style={styles.appButtonText}>{title}</Text>
  </TouchableOpacity>
);

If you want to change the opacity for all of the custom buttons in your app, use the defaultProps property. defaultProps is a React component property that sets default values for the prop argument.

After you’ve imported TouchableOpacity, add the following line at the top of the file.

TouchableOpacity.defaultProps = { activeOpacity: 0.8 };

The onPress prop expects a function or a function reference that will execute when the user presses the button.

The full code for this section is as follows:

import React from "react";
import { View, Button, StyleSheet, TouchableOpacity, Text } from "react-native";

TouchableOpacity.defaultProps = { activeOpacity: 0.8 };

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity onPress={onPress} style={styles.appButtonContainer}>
    <Text style={styles.appButtonText}>{title}</Text>
  </TouchableOpacity>
);

const App = () => {
  return (
    <View style={styles.screenContainer}>
      <AppButton title="Hey there!" size="sm" backgroundColor="#007bff" />
    </View>
  );
};

const styles = StyleSheet.create({
  screenContainer: {
    flex: 1,
    justifyContent: "center",
    padding: 16
  },
  appButtonContainer: {
    elevation: 8,
    backgroundColor: "#009688",
    borderRadius: 10,
    paddingVertical: 10,
    paddingHorizontal: 12
  },
  appButtonText: {
    fontSize: 18,
    color: "#fff",
    fontWeight: "bold",
    alignSelf: "center",
    textTransform: "uppercase"
  }
});

export default App;

Add styles to buttons in React Native by adding more props

Since it’s a custom button component, you have the liberty of piling on additional props. For example, you can add a prop to change the button size or change the background color.

const AppButton = ({ onPress, title, size, backgroundColor }) => (
  <TouchableOpacity
    onPress={onPress}
    style={[
      styles.appButtonContainer,
      size === "sm" && {
        paddingHorizontal: 8,
        paddingVertical: 6,
        elevation: 6
      },
      backgroundColor && { backgroundColor }
    ]}
  >
    <Text style={[styles.appButtonText, size === "sm" && { fontSize: 14 }]}>
      {title}
    </Text>
  </TouchableOpacity>
);

// ...
<AppButton title="Hey there!" size="sm" backgroundColor="#007bff" />;

You’ll see the following result on your screen.

Our second custom-styled button

Custom button with linear gradient background

By default, React Native doesn’t have an API to create a linear gradient background in a container. Luckily, there’s another utility library for React Native that you can use to create linear gradient colors. It is very flexible and offers various props to customize your pre-built component’s gradient style according to your needs. You can learn more about the linear gradient library on GitHub.

Run the following command to include the library in your project.

npm i react-native-linear-gradient

Next, import the <LinearGradient /> component from the react-native-linear-gradient library.

import LinearGradient from "react-native-linear-gradient";

You‘ll need to make some adjustments in the <AppButton /> component. Wrap the <TouchableOpacity /> component around the <LinearGradient /> component and add the style prop to the <LinearGradient /> component.

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity onPress={onPress}>
    <LinearGradient
      colors={["#004d40", "#009688"]}
      style={styles.appButtonContainer}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </LinearGradient>
  </TouchableOpacity>
);

The colors prop in LinearGradient accepts an array, which contains the color values that will be used to create the linear gradient.

Our custom button with a gradient background

Check out the complete code for this section below.

import React from "react";
import { View, Button, StyleSheet, TouchableOpacity, Text } from "react-native";
import LinearGradient from "react-native-linear-gradient";

TouchableOpacity.defaultProps = { activeOpacity: 0.8 };

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity onPress={onPress}>
    <LinearGradient
      colors={["#004d40", "#009688"]}
      style={styles.appButtonContainer}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </LinearGradient>
  </TouchableOpacity>
);

const App = () => {
  return (
    <View style={styles.screenContainer}>
      <AppButton title="Hey there!" size="sm" backgroundColor="#007bff" />
    </View>
  );
};

const styles = StyleSheet.create({
  screenContainer: {
    flex: 1,
    justifyContent: "center",
    padding: 16
  },
  appButtonContainer: {
    elevation: 8,
    borderRadius: 10,
    paddingVertical: 10,
    paddingHorizontal: 12
  },
  appButtonText: {
    fontSize: 18,
    color: "#fff",
    fontWeight: "bold",
    alignSelf: "center",
    textTransform: "uppercase"
  }
});

export default App;

Let’s see another example. The following <AppButton/> definition creates a gradient-style-based custom button with a blue-color gradient and a neon green light line.

const AppButton = ({ onPress, title }) => (
  <TouchableOpacity onPress={onPress}>
    <LinearGradient
      colors={["#1387d4", "#259399", "#0b466e"]}
      start={{x: 0, y: 0}} // Gradient starting coordinates
      end={{x: 0, y: 0.5}} // Gradient ending coordinates
      style={styles.appButtonContainer}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </LinearGradient>
  </TouchableOpacity>
);

Here we can use the start and end props to control the gradient position. The above component definition produces the following button.

Custom button with a green gradient

Similarly, you can build your own gradient button style matching your styling requirements in design prototypes.

Build a custom button with vector icons

React Native developers often have to create buttons with icons according to the design prototypes they receive. These icon buttons are widely used in login screens, dashboards, and various mobile application screens. Now, we’re going to create some buttons by using several vector icons.

There are two key approaches for creating these special buttons:

  1. Building a button component from scratch by wrapping a <Text/> element and <Image/> element with <View/>
  2. Using pre-built components from a library

You can easily create these types of buttons with the react-native-vector-icons library.

Let’s create several different buttons for a sign-in page. Here’s what our sign-in page will look like when we’re finished.

Custom buttons using vector icons

First, add the vector icons library with the following command.

npm i react-native-vector-icons

Next, import the <Icon /> component from the library, as shown below.

import Icon from 'react-native-vector-icons/FontAwesome';

Now we can create a reusable icon button with the following definition.

const AppButton = ({ onPress, icon, title, backgroundColor }) => (
  <View style={styles.appButtonContainer}>
    <Icon.Button
      name={icon}
      backgroundColor={backgroundColor}
      onPress={onPress}
      style={styles.appButton}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </Icon.Button>
  </View>
);

The icon button component is ready. You can configure it by sending different props: onPress, icon, title, and backgroundColor. Check out the source code for the sample sign-in page below.

import React from "react";
import { View, StyleSheet, Text } from "react-native";
import Icon from 'react-native-vector-icons/FontAwesome';

const AppButton = ({ onPress, icon, title, backgroundColor }) => (
  <View style={styles.appButtonContainer}>
    <Icon.Button
      name={icon}
      backgroundColor={backgroundColor}
      onPress={onPress}
      style={styles.appButton}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </Icon.Button>
  </View>
);

const App = () => {
  return (
    <View style={styles.screenContainer}>
      <AppButton icon="sign-in" title="Login with password" backgroundColor="#777"/>
      <AppButton icon="facebook" title="Login with Facebook" backgroundColor="#3b5998"/>
      <AppButton icon="github" title="Login with GitHub" backgroundColor="#14191e"/>
    </View>
  );
};

const styles = StyleSheet.create({
  screenContainer: {
    flex: 1,
    justifyContent: "center",
    padding: 80,
    backgroundColor: "#555",
  },
  appButton: {
    padding: 12,
  },
  appButtonText: {
    fontSize: 17,
  },
  appButtonContainer: {
    paddingVertical: 10,
    paddingHorizontal: 12,
  },
});

export default App;

The above source code configures the same <AppButton/> component definition by sending different props.

Controlling button styles using state

As in any React application, you can add styles to your component based on the current value of the state. For example, if you want to disable a button for a certain period of time after it’s pressed, the button must have a disabled background color so that the user knows it’s temporarily inactive.

Add a style property inside the StyleSheet object to represent the disabled color. For this example, we’ll use black.

const styles = StyleSheet.create({
  // ...
  appButtonDisabled: {
    backgroundColor: "#000"
  }
});

Next, refactor the <AppButton /> component and use the useState Hook to change the disabled state.

const AppButton = ({ title }) => {
  const [isDisabled, setDisabled] = useState(false);

  const handlePress = () => {
    setDisabled(true);
    setTimeout(() => setDisabled(false), 3000);
  };

  return (
    <TouchableOpacity
      onPress={handlePress}
      style={[
        styles.appButtonContainer,
        isDisabled && styles.appButtonDisabled
      ]}
      disabled={isDisabled}
    >
      <Text style={styles.appButtonText}>{title}</Text>
    </TouchableOpacity>
  );
};

You can pass a disabled prop to the TouchableOpacity component to disable the onPress behavior. You can pass an array of style objects to the style prop.

When isDisabled is set to true, you can add the appButtonDisabled property to the style prop array using the && operator.

The above implementation disables the button for three seconds by displaying a different style, as shown below.

The button appears different while it's disabled for three seconds

How to style React Native buttons with styled-components

styled-components is a CSS-in-JS library that enables you to write each component with its own style and encapsulate the code in a single location.

React Native follows a certain specification for styling these components. For example, all CSS property names must be written in camelCasebackground-color should be specified as backgroundColor, border-width as borderWidth, etc.

This can be a little disorienting for a developer who is approaching mobile app development from a web development background. The styled-components library enables you to write native CSS for styling a React Native component. Under the hood, styled-components simply converts the CSS text into a React Native StyleSheet object.

Run the following command to install styled-components.

yarn add styled-components

Import the library.

import styled from "styled-components";

Refactor the code to implement styled-components.

Replace the TouchableOpacity and Text components with ButtonContainer and ButtonText, respectively. These new components will be created using the syntax from styled-components.

const AppButton = ({ onPress, title }) => (
  <ButtonContainer onPress={onPress}>
    <ButtonText>{title}</ButtonText>
  </ButtonContainer>
);

styled-components uses tagged template literals to style the components using backticks (`). Each styled component must have a React Native component attached to it.

const ButtonContainer = styled.TouchableOpacity``;

const ButtonText = styled.Text``;

Inside the backticks, add your CSS rules.

const ButtonContainer = styled.TouchableOpacity`
  elevation: 8;
  border-radius: 10px;
  padding-vertical: 10px;
  padding-horizontal: 12px;
`;

const ButtonText = styled.Text`
  font-size: 18;
  color: #fff;
  font-weight: bold;
  align-self: center;
  text-transform: uppercase;
`;

Putting everything together, your code should look like this with the wrapper view for buttons:

import React from "react";
import { View, Button, TouchableOpacity, Text } from "react-native";
import styled from "styled-components";

TouchableOpacity.defaultProps = { activeOpacity: 0.8 };

const ButtonContainer = styled.TouchableOpacity`
  elevation: 8;
  border-radius: 10px;
  padding-vertical: 10px;
  padding-horizontal: 12px;
  background-color: #555;
`;

const ButtonText = styled.Text`
  font-size: 18px;
  color: #fff;
  font-weight: bold;
  align-self: center;
  text-transform: uppercase;
`;

const AppContainer = styled.View`
  flex: 1;
  justify-content: center;
  padding: 16px;
  background-color: #eee;
`;

const AppButton = ({ onPress, title }) => (
  <ButtonContainer onPress={onPress}>
    <ButtonText>{title}</ButtonText>
  </ButtonContainer>
);

const App = () => {
  return (
    <AppContainer>
      <AppButton title="Hey there!"/>
    </AppContainer>
  );
};

export default App;

The above source code produces the following application using CSS-like syntax from the styled-components library.

Our button created with styled-components

Emotion is also a CSS-in-JS library that supports styling React Native components, so you can use the @emotion-native package for creating custom React Native buttons with CSS syntax. Emotion offers almost all features that styled-components offers with very similar syntax.

Conclusion

Some other npm packages that wrap <TouchableOpacity/> offer pre-built custom buttons for React Native with some features like icon support, theming, custom coloring, etc. But, those libraries are not very popular among developer communities due to the easiness of custom button creation and fully-featured UI kits. For example, you can build any custom button easily with the steps explained in this tutorial. On the other hand, you can use a fully-featured UI kit like Native Base, which offers many pre-built custom button styles.

As a developer, you must build UI components to match whatever reference or design your design team comes up with. It’s your responsibility to make the UI components look precisely as they’re outlined in your client’s plan or prototype.

There’s so much more you can do, but the steps in this guide will help you find your footing as you start creating custom UI components with React Native.

LogRocket: Instantly recreate issues in your React Native apps.

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — .

Gaurav Singhal Gaurav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, web scraping, Angular, and React.

2 Replies to “How to create and style custom buttons in React…”

Leave a Reply