Tutorial

How To Build Custom Inputs in React Native

Updated on June 29, 2021
Default avatar

By Alex Jover Morales

How To Build Custom Inputs in React Native

This tutorial is out of date and no longer maintained.

Introduction

React Native provides us with a great range of components to design and build fully native user interfaces. These include buttons, views, lists, progress bars, and more.

We also have form inputs components like TextInput and Picker. However, when we use them multiple times across an application we might find ourselves wanting a unified reusable pattern.

Note: Picker has been deprecated and will be removed from React Native core. It can be imported from @react-native-picker/picker.

In this article, you will build your own custom form inputs for React Native applications.

Prerequisites

To complete this tutorial, you’ll need:

This tutorial was verified with Node v16.4.0, npm v7.19.0, react v16.13.1, and react-native v0.63.4.

Step 1 – Setting Up the Project

First, create a new React Native app by entering the following command in your terminal:

  1. npx react-native init ReactNativeCustomInputs --version 0.64.2

Then, navigate to the new directory:

  1. cd ReactNativeCustomInputs

And start the application for iOS:

  1. npm run ios

Alternatively, for Android:

  1. npm run android

Note: If you experience any problems, you may need to consult troubleshooting issues for React Native CLI.

This will create a skeleton project for you.

Step 2 – Customizing Input and Select Components

There are multiple benefits to having our own input and select components. For example, they both usually have labels and a similar style throughout the app, so we can group that logic together.

Additionally, we can provide a simpler and common API. Both TextInput and Picker use different properties for getting and updating the value: value vs selectedValue and onChangeText vs onValueChange. Furthermore, every time we create a Picker component we must create a list of Picker.Item, which can be avoided if we assume a convention and pass an array of key-values to the component.

In order to solve these issues, let’s build custom AppInput and AppSelect components.

First, open the App.js file with your code editor.

Let’s start by creating a BaseInput component where we can add common functionality, such as the label:

App.js
import React from 'react';
import { View, StyleSheet, Text } from 'react-native';

const styles = StyleSheet.create({
  baseInput: {
    paddingVertical: 6,
  },
});

const BaseInput = ({ children, label }) => (
  <View style={styles.baseInput}>
    <Text>{label}</Text>
    {children}
  </View>
);

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { };
  }

  render() {
    return (
      <View style={{ flex: 1, padding: 40 }}>
        <BaseInput
          label="Example"
        />
      </View>
    );
  }
}

This code also establishes a common style using the StyleSheet API and a label using the Text component.

To ensure this input is reusable, the children are passed to it and rendered inside it.

Now, you can build an AppInput component using the BaseInput component and React Native’s TextInput. Revisit App.js and add the following lines of code:

App.js
import React from 'react';
import { View, StyleSheet, Text, TextInput } from 'react-native';

// ...

const AppInput = ({ children, value, onChange, ...props }) => (
  <BaseInput {...props}>
    <TextInput
      value={value}
      onChangeText={onChange}
    />
  </BaseInput>
);

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     input: ''
    };
  }

  render() {
    const { input } = this.state;

    return (
      <View style={{ flex: 1, padding: 40 }}>
        <AppInput
          label="Name"
          value={input}
          onChange={input => this.setState({ input })}
        />
      </View>
    );
  }
}

The properties that the AppInput doesn’t use are passed to the BaseInput component, along with a TextInput.

Now, you can build an AppSelect component using the BaseInput component and React Native’s Picker. Revisit App.js and add the following lines of code:

App.js
import React from 'react';
import { View, StyleSheet, Text, TextInput, Picker } from 'react-native';

// ...

const AppSelect = ({ children, value, onChange, items, ...props }) => (
  <BaseInput {...props}>
    <Picker
      selectedValue={value}
      onValueChange={onChange}
    >
      {items.map(item => (
        <Picker.Item
          key={item.value}
          label={item.label}
          value={item.value}
        />
      ))}
    </Picker>
  </BaseInput>
);

const countries = [
  { label: 'Spain', value: 'es' },
  { label: 'USA', value: 'us' },
];

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     input: '',
     select: {},
    };
  }

  render() {
    const { input, select } = this.state;

    return (
      <View style={{ flex: 1, padding: 40 }}>
        <AppInput
          label="Name"
          value={input}
          onChange={input => this.setState({ input })}
        />
        <AppSelect
          label="Country"
          items={countries}
          value={select}
          onChange={select => this.setState({ select })}
        />
      </View>
    );
  }
}

Both components share the common label, value, and onChange props, making the code simpler and easier to use and understand.

Step 3 – Adding Styles

So far the BaseInput component has a default baseInput style that we’re applying from the stylesheet, but… What if we want to override it?

React Native lets us pass an array to the style property on the components, so we can take advantage of that by passing an optional style property.

Let’s do that in BaseInput:

App.js
const BaseInput = ({ style, children, label }) => (
  <View style={[styles.baseInput, style]}>
    <Text>{label}</Text>
    {children}
  </View>
);

Given the fact that we’re passing down the properties on the AppInput and AppSelect components, now if we pass-in a style prop it will override the default styles:

App.js
<AppInput
  style={{ flex: 1, paddingVertical: 33 }}
  label="Name"
  value={input}
  onChange={input => this.setState({ input })}
/>

Following that technique, we can customize the other parts of the components by passing multiple style props, such as rootStyle, inputStyle, etc.

Conclusion

In this article, you built your own custom form inputs for React Native applications. This allowed you to reuse common functionality and apply consistency to your Input and Select components.

If you’d like to learn more about React, take a look at our How To Code in React.js series, or check out our React topic page for exercises and programming projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Alex Jover Morales

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel