tcomb-form-native is looking for maintainers. If you're interested in helping, a great way to get started would just be to start weighing-in on GitHub issues, reviewing and testing some PRs.
npm install tcomb-form-native
| Version | React Native Support | Android Support | iOS Support |
|---|---|---|---|
| 0.5 - 0.6.1 | 0.25.0 - 0.35.0 | 7.1 | 10.0.2 |
| 0.4 | 0.20.0 - 0.24.0 | 7.1 | 10.0.2 |
| 0.3 | 0.1.0 - 0.13.0 | 7.1 | 10.0.2 |
| Complies with react-native-version-support-table |
The tcomb library provides a concise but expressive way to define domain models in JavaScript.
The tcomb-validation library builds on tcomb, providing validation functions for tcomb domain models.
This library builds on those two and the awesome react-native.
With tcomb-form-native you simply call <Form type={Model} /> to generate a form based on that domain model. What does this get you?
JSON Schemas are also supported via the (tiny) tcomb-json-schema library.
Note. Please use tcomb-json-schema ^0.2.5.
The look and feel is customizable via react-native stylesheets and templates (see documentation).
http://react.rocks/example/tcomb-form-native
https://github.com/bartonhammond/snowflake React-Native, Tcomb, Redux, Parse.com, Jest - 88% coverage
// index.ios.js
'use strict';
var React = require('react-native');
var t = require('tcomb-form-native');
var { AppRegistry, StyleSheet, Text, View, TouchableHighlight } = React;
var Form = t.form.Form;
// here we are: define your domain model
var Person = t.struct({
name: t.String, // a required string
surname: t.maybe(t.String), // an optional string
age: t.Number, // a required number
rememberMe: t.Boolean // a boolean
});
var options = {}; // optional rendering options (see documentation)
var AwesomeProject = React.createClass({
onPress: function () {
// call getValue() to get the values of the form
var value = this.refs.form.getValue();
if (value) { // if validation fails, value will be null
console.log(value); // value here is an instance of Person
}
},
render: function() {
return (
<View style={styles.container}>
{/* display */}
<Form
ref="form"
type={Person}
options={options}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
justifyContent: 'center',
marginTop: 50,
padding: 20,
backgroundColor: '#ffffff',
},
buttonText: {
fontSize: 18,
color: 'white',
alignSelf: 'center'
},
button: {
height: 36,
backgroundColor: '#48BBEC',
borderColor: '#48BBEC',
borderWidth: 1,
borderRadius: 8,
marginBottom: 10,
alignSelf: 'stretch',
justifyContent: 'center'
}
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
Output:
(Labels are automatically generated)

Ouput after a validation error:

getValue()Returns null if the validation failed, an instance of your model otherwise.
Note. Calling
getValuewill cause the validation of all the fields of the form, including some side effects like highlighting the errors.
validate()Returns a ValidationResult (see tcomb-validation for a reference documentation).
The Form component behaves like a controlled component:
var Person = t.struct({
name: t.String,
surname: t.maybe(t.String)
});
var AwesomeProject = React.createClass({
getInitialState() {
return {
value: {
name: 'Giulio',
surname: 'Canti'
}
};
},
onChange(value) {
this.setState({value});
},
onPress: function () {
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
render: function() {
return (
<View style={styles.container}>
<Form
ref="form"
type={Person}
value={this.state.value}
onChange={this.onChange}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
The onChange handler has the following signature:
(raw: any, path: Array<string | number>) => void
where
raw contains the current raw value of the form (can be an invalid value for your model)path is the path to the field triggering the changeWarning. tcomb-form-native uses
shouldComponentUpdateaggressively. In order to ensure that tcomb-form-native detect any change totype,optionsorvalueprops you have to change references:
var Type = t.struct({
disable: t.Boolean, // if true, name field will be disabled
name: t.String
});
// see the "Rendering options" section in this guide
var options = {
fields: {
name: {}
}
};
var AwesomeProject = React.createClass({
getInitialState() {
return {
options: options,
value: null
};
},
onChange(value) {
// tcomb immutability helpers
// https://github.com/gcanti/tcomb/blob/master/docs/API.md#updating-immutable-instances
var options = t.update(this.state.options, {
fields: {
name: {
editable: {'$set': !value.disable}
}
}
});
this.setState({options: options, value: value});
},
onPress: function () {
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
render: function() {
return (
<View style={styles.container}>
<Form
ref="form"
type={Type}
options={this.state.options}
value={this.state.value}
onChange={this.onChange}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
You can get access to a field with the getComponent(path) API:
var Person = t.struct({
name: t.String,
surname: t.maybe(t.String),
age: t.Number,
rememberMe: t.Boolean
});
var AwesomeProject = React.createClass({
componentDidMount() {
// give focus to the name textbox
this.refs.form.getComponent('name').refs.input.focus();
},
onPress: function () {
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
render: function() {
return (
<View style={styles.container}>
<Form
ref="form"
type={Person}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
var Person = t.struct({
name: t.String,
surname: t.maybe(t.String),
age: t.Number,
rememberMe: t.Boolean
});
var AwesomeProject = React.createClass({
getInitialState() {
return { value: null };
},
onChange(value) {
this.setState({ value });
},
clearForm() {
// clear content from all textbox
this.setState({ value: null });
},
onPress: function () {
var value = this.refs.form.getValue();
if (value) {
console.log(value);
// clear all fields after submit
this.clearForm();
}
},
render: function() {
return (
<View style={styles.container}>
<Form
ref="form"
type={Person}
value={this.state.value}
onChange={this.onChange.bind(this)}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
Say I have an iOS Picker, depending on which option is selected in this picker I want the next component to either be a checkbox or a textbox:
const Country = t.enums({
'IT': 'Italy',
'US': 'United States'
}, 'Country');
var AwesomeProject = React.createClass({
// returns the suitable type based on the form value
getType(value) {
if (value.country === 'IT') {
return t.struct({
country: Country,
rememberMe: t.Boolean
});
} else if (value.country === 'US') {
return t.struct({
country: Country,
name: t.String
});
} else {
return t.struct({
country: Country
});
}
},
getInitialState() {
const value = {};
return { value, type: this.getType(value) };
},
onChange(value) {
// recalculate the type only if strictly necessary
const type = value.country !== this.state.value.country ?
this.getType(value) :
this.state.type;
this.setState({ value, type });
},
onPress() {
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
render() {
return (
<View style={styles.container}>
<t.form.Form
ref="form"
type={this.state.type}
value={this.state.value}
onChange={this.onChange}
/>
<TouchableHighlight style={styles.button} onPress={this.onPress} underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
);
}
});
By default fields are required:
var Person = t.struct({
name: t.String, // a required string
surname: t.String // a required string
});
In order to create an optional field, wrap the field type with the t.maybe combinator:
var Person = t.struct({
name: t.String,
surname: t.String,
email: t.maybe(t.String) // an optional string
});
The postfix " (optional)" is automatically added to optional fields.
You can customise the postfix value or setting a postfix for required fields:
t.form.Form.i18n = {
optional: '',
required: ' (required)' // inverting the behaviour: adding a postfix to the required fields
};
In order to create a numeric field, use the t.Number type:
var Person = t.struct({
name: t.String,
surname: t.String,
email: t.maybe(t.String),
age: t.Number // a numeric field
});
tcomb-form-native will convert automatically numbers to / from strings.
In order to create a boolean field, use the t.Boolean type:
var Person = t.struct({
name: t.String,
surname: t.String,
email: t.maybe(t.String),
age: t.Number,
rememberMe: t.Boolean // a boolean field
});
Booleans are displayed as SwitchIOSs.
In order to create a date field, use the t.Date type:
var Person = t.struct({
name: t.String,
surname: t.String,
email: t.maybe(t.String),
age: t.Number,
birthDate: t.Date // a date field
});
Dates are displayed as DatePickerIOSs under iOS and DatePickerAndroid or TimePickerAndroid under Android, depending on the mode selected (date or time).
Under Android, use the fields option to configure which mode to display the Picker:
// see the "Rendering options" section in this guide
var options = {
fields: {
birthDate: {
mode: 'date' // display the Date field as a DatePickerAndroid
}
}
};
config optionThe bundled template will render an iOS UIDatePicker component, but collapsed into a touchable component in order to improve usability. A config object can be passed to customize it with the following parameters:
| Key | Value |
|---|---|
animation |
The animation to collapse the date picker. Defaults to Animated.timing. |
animationConfig |
The animation configuration object. Defaults to {duration: 200} for the default animation. |
format |
A (date) => String(date) kind of function to provide a custom date format parsing to display the value. Optional, defaults to `(date) => S |
$ claude mcp add tcomb-form-native \
-- python -m otcore.mcp_server <graph>