A simple declarative API for creating cross-platform native-appearing forms
React Native Forms
A simple, declarative API for creating cross-platform, native-appearing forms with React Native.
I wrote this library a number of months ago for a use-case at work, when React Native was still quite young, comparatively. I open sourced it in the general spirit of sharing code that had been useful to me, but with the vicissitudes of life being what they are, I didn't have the opportunity to keep it up to date, and it's become a bit antiquated. If you want to use it, go for it! I'm still using it in production. But I don't have time to update it or add features, though I will take PRs. For similiar UI functionality within a much larger and better-maintained project, I'd recommend checking out React Native Elements. Thanks for stopping by!
React Native Forms is a cross-platform library for creating native-looking forms using [React Native](https://github.com/facebook/react-native).
Some benefits of React Native Forms:
- Works for iOS and Android out of the box.
- Easily extensible, allowing for the creation of custom appearances and behaviors.
- Exposes functions for handling form data outside of the form components, for easy use in Flux /Redux applications.
- Customizable form validation API. Inject
validator
functions as props to all your form components, and get errors by simply callinggetValidationErrors
on your form to get a serialized copy of all your validation errors. - Simple, declarative syntax - you don't have to write any styles at all to produce a form, if you don't want to (although all default styles are overridable)
<Form ref={(form) => this.form = form}>
<Section title={'SECTION'}>
<PushButtonCell ref='push' title='Push me!'/>
<TextInputCell
ref='input'
inputProps={{placeholder: 'Input here'}}
/>
</Section>
</Form>
Then, you can get the the serialized data from your form by simply calling this.form.getData();
- Plus, a library of common form components available out of the box, for iOS and Android:
Installation
npm install react-native-forms --save
The package has no native dependencies. In the example project, I use the excellent react-native-vector-icons for icons in the example library and screenshots, but React Native Forms does not depend on it.
You can then require any component or function from the library:
const { Form, Section, createValidator } = require('react-native-forms');
Or if you use ES6 syntax:
import { Form, Section, createValidator } from 'react-native-forms';
Documentation
Form Validation
The top-level Form
component exposes functions and props to handle data in the form.
- Functions called on the
Form
component. - Function props passed to the
Form
component.
If you are developing your own component for use with React Native Forms, note that anonChange([ref], [value])
and onPress([ref])
function is injected into each child component of a Form
, and you will need to make sure you call this.props.onChange(value)
or this.props.onPress()
at the appropriate times.
Additionally, each child component has a validator
prop, which you can use to pass a function to validate the component's value. See Form Validation below for more information.
Method Reference
getData()
Returns a copy of the form's data, expressed as an object, in the shape:
{
sectionRef: {
firstChildRef: firstChildValue,
secondChildRef: secondChildValue,
},
};
getValidationErrors()
Returns a copy of the form's validation errors, expressed as an object of error objects in the shape:
{
sectionRef: {
childRef: childValidationErrMessage,
},
}
onChange([ref], [value])
Where ref
is the ref of the child component whose value has changed, and value
is the new value of the child component.
Note: it is not recommended to perform validation as a result of this function. Instead, inject a validator into the child component through the validator
prop, and listen for validation errors at the the top-level Form
's getValidationErrors
or onValidationError
functions.
onPress([ref])
Where ref
is the ref of the child component responding to the touch event.
This is called by each component that respond to touch events. Examples from the library would include PushButtonCell
or ButtonCell
.
onValidationError([sectionRef], [sectionData])
Where sectionRef
is the ref of the child section component whose validation function has failed. The error message is set as a value on whichever child of the section failed its validator
prop.
You'll probably never need to use this function, since you probably only want to alert users of validation errors on submit.
Form Validation
Each validation function takes a single argument, value
, which contains the value of the component it's validating. If validation fails, the function throws an error with a specified message.
The library exposes one generic function for creating validators: createValidator
.
createValidator([validator], [options])
Returns a validator function, created with specified options. You can pass either a validator from the library (such as emailValidator
) or one of your own.
Arguments
-
[
validator(value): boolean
] Function: This function is passed the value of the component the validator is passed to as a prop, and should return the boolean value of whether the component's value is valid. -
[
options
] Object: Customizes the behavior of the validator function.- [
errorMessage
] String: The message that the validator should fail with.
- [
Components
Out of the box, React Native Forms comes with
ActionSheetCell
(ios only)ButtonCell
DatePickerCell
(ios only)PushButtonCell
SwitchCell
TextInputCell
I've tried to make these components as consistent and customizable as possible, but PR's are highly welcome to improve their API, as well as to add more common form components, and improve documentation. I'm also working to provide more components.
To learn how to use them, see their usage in the example project, as well as the available propTypes
in each component's source.
Creating Custom Components
You can write your own components, and give them whatever styles or behaviors you want. Form
and Section
components are agnostic as to the styles and behaviors of their children.
Remember that the parent Section
will automatically inject onPress
and onChange
props into your component, and bind the child's refs
to the function. To make your component work with React Native Form's data API, simply call this.props.onChange(value)
or this.props.onPress()
at appropriate times. For more information, see the example project.
FAQ
##### When I navigate to the form, I get an error: RCTUIManager.m Error frame is not a descendant of < RCTShadowView >This error happens when you have multiple views listening for keyboard events. This can happen, for example, when multiple scroll views inside a navigation stack are listening to keyboard events in order to scroll to a text input.
You can fix this by unmounting any components which are listening for keyboard events before presenting another. React Native Forms depends on react-native-keyboard-aware-scroll-view, which listens for keyboard events if you've enabled the keyboardAware
prop on your top-level Form
component.
I'd like to fix this and allow for keyboard aware child forms. This seems to be possible. (For example, see this discussion in react-native). PR's are welcome.