Custom Inputs in React Native

Alex Jover Morales

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 🦄

  Tweet It

🕵 Search Results

🔎 Searching...