While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

React Native gives us a great range of components to design and build fully native UI’s, such as buttons, views, lists, progress bars and more.

We also have form inputs components like TextInput and Picker, but when we use them multiple times across an application, their use can start to be repetitive since they’re a bit basic. Let’s see how can we build our own form inputs.

Custom Input and Select

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.

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

import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; const styles = StyleSheet.create({ baseInput: { paddingVertical: 6, }, }); const BaseInput = ({ children, label }) => ( <View style={styles.baseInput}> <Text>{label}</Text> {children} </View> );

I added a common style using the StyleSheet API and a label using the Text component.

In order to reuse that and to be able to pass any kind of input component to it, we’re rendering children just below the label. In that way, we can easily create the AppInput component:

import { TextInput } from 'react-native'; // ... const AppInput = ({ children, value, onChange, ...props }) => ( <BaseInput {...props}> <TextInput value={value} onChangeText={onChange} /> </BaseInput> );

We’re basically passing the properties that the AppInput doesn’t use down to the BaseInput component, along with a TextInput.

Applying the same technique, we can create a AppSelect component using React Native’s Picker component:

import { 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> );

Finally, we can use them as follows in our App component:

class App extends React.Component { 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> ); } }

As you can see, they share the common label , value and onChange props, making the code simpler and easier to use and understand.

Styles Composition

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 let’s 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:

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:

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

Following that technique, we can easily customize the other parts of the components by passing multiple style props, such as rootStyle , inputStyle , etc. But I’ll leave that up to you 😜.

Wrapping Up

We’ve seen how to create our own form input components in React Native so that we can reuse common functionality and our code becomes more DRY, concise and easier to read and understand.

Don’t forget to check out the online demo!

Stay cool 🦄