<commit_before>Table of Contents
=================

  * [Get started](#get-started)
    * [Setup](#setup)
    * [Working example](#working-example)
    * [API](#api)
      * [getValue()](#getvalue)
      * [validate()](#validate)
      * [Adding a default value and listen to changes](#adding-a-default-value-and-listen-to-changes)
      * [How to get access to a field](#how-to-get-access-to-a-field)
      * [Submitting the form](#submitting-the-form)
      * [Customised error messages](#customised-error-messages)
  * [Types](#types)
    * [Required field](#required-field)
    * [Optional field](#optional-field)
    * [Numbers](#numbers)
    * [Refinements](#refinements)
    * [Booleans](#booleans)
    * [Dates](#dates)
    * [Enums](#enums)
    * [Lists](#lists)
    * [Nested structures](#nested-structures)
  * [Rendering options](#rendering-options)
    * [Struct options](#struct-options)
      * [Automatically generated placeholders](#automatically-generated-placeholders)
      * [Fields order](#fields-order)
      * [Legend](#legend)
      * [Help message](#help-message)
      * [Error message](#error-message)
      * [Disabled](#disabled)
      * [Fields configuration](#fields-configuration)
      * [Look and feel](#look-and-feel)
    * [List options](#list-options)
      * [Items configuration](#items-configuration)
      * [Internationalization](#internationalization)
      * [Buttons configuration](#buttons-configuration)
    * [Textbox options](#textbox-options)
      * [Type attribute](#type-attribute)
      * [Label](#label)
      * [Attributes and events](#attributes-and-events)
      * [Styling](#styling)
    * [Checkbox options](#checkbox-options)
    * [Select options](#select-options)
      * [Null option](#null-option)
      * [Options order](#options-order)
      * [Custom options](#custom-options)
      * [Render as a radio group](#render-as-a-radio-group)
      * [Multiple select](#multiple-select)
    * [Date options](#date-options)
      * [Fields order](#fields-order-1)
  * [Customizations](#customizations)
    * [Templates](#templates)
    * [Transformers](#transformers)
    * [Custom factories](#custom-factories)
  * [Bootstrap extras](#bootstrap-extras)
    * [Textbox](#textbox)
      * [Addons](#addons)
      * [Size](#size)
    * [Select](#select)
    * [Struct](#struct)
  * [General configuration](#general-configuration)
    * [Changing the default language](#changing-the-default-language)
    * [Changing the default skin](#changing-the-default-skin)

# Get started

## Setup

```sh
$ npm install tcomb-form
```
Note: Use tcomb-form@0.6.x with react@0.13.x. See [#200](https://github.com/gcanti/tcomb-form/issues/200).

## Working example

```js
var React = require('react');
var ReactDOM = require('react/lib/ReactDOM');
var t = require('tcomb-form');
var Form = t.form.Form;

// define your domain model with tcomb
// https://github.com/gcanti/tcomb
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var App = React.createClass({

  save() {
    // call getValue() to get the values of the form
    var value = this.refs.form.getValue();
    // if validation fails, value will be null
    if (value) {
      // value here is an instance of Person
      console.log(value);
    }
  },

  render() {
    return (
      <div>
        <Form
          ref="form"
          type={Person}
        />
        <button onClick={this.save}>Save</button>
      </div>
    );
  }

});

ReactDOM.render(<App />, document.getElementById('app'));
```

> **Note**. Labels are automatically generated.

## API

### `getValue()`

Returns `null` if the validation failed; otherwise returns an instance of your model.

> **Note**. Calling `getValue` will 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](https://github.com/gcanti/tcomb-validation) for a reference documentation).

### Adding a default value and listening to changes

The `Form` component behaves like a [controlled component](https://facebook.github.io/react/docs/forms.html):

```js
var App = React.createClass({

  getInitialState() {
    return {
      value: {
        name: 'Giulio',
        surname: 'Canti'
      }
    };
  },

  onChange(value) {
    this.setState({value});
  },

  save() {
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {
    return (
      <div>
        <Form
          ref="form"
          type={Person}
          value={this.state.value}
          onChange={this.onChange}
        />
        <button onClick={this.save}>Save</button>
      </div>
    );
  }

});
```

The `onChange` handler has the following signature:

```
(raw: any, path: Array<string | number>, kind?) => 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 change
- `kind` specify the kind of change (when `undefined` means a value change)
  + `'add'` list item added
  + `'remove'` list item removed
  + `'moveUp'` list item moved up
  + `'moveDown'` list item moved down

### Accessing fields

You can get access to a field with the `getComponent(path)` API:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var App = React.createClass({

  onChange(value, path) {
    // validate a field on every change
    this.refs.form.getComponent(path).validate();
  },

  render() {
    return (
      <div>
        <Form ref="form"
          type={Person}
          onChange={this.onChange}
        />
      </div>
    );
  }

});
```

### Submitting the form

The output of the `Form` component is a `fieldset` tag containing your fields. You can submit the form by wrapping the output with a `form` tag:

```js
var App = React.createClass({

  onSubmit(evt) {
    var value = this.refs.form.getValue();
    if (!value) {
      // there are errors, don't send the form
      evt.preventDefault();
    } else {
      // everything ok, let the form fly...
      // ...or handle the values contained in the
      // `value` variable with js
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <Form
          ref="form"
          type={Person}
        />
        <button type="submit">Save</button>
      </form>
    );
  }

});
```

### Customised error messages

You can add a custom error message with the `error` options (see [Error message](#error-message) section).
Another way is adding a

```
getValidationErrorMessage(value, path, context)
```

 static function to a type, where:

- `value` is the (parsed) current value of the component.
- `path` is the path of the value being validated
- `context` is the value of the `context` prop. Also it contains a reference to the component options.


```js
var Age = t.refinement(t.Number, function (n) { return n >= 18; });

// if you define a getValidationErrorMessage function, it will be called on validation errors
Age.getValidationErrorMessage = function (value, path, context) {
  return 'bad age, locale: ' + context.locale;
};

var Schema = t.struct({
  age: Age
});

var App = React.createClass({

  onSubmit(evt) {
    evt.preventDefault();
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <t.form.Form
          ref="form"
          type={Schema}
          context={{locale: 'it-IT'}}
        />
        <button type="submit" className="btn btn-primary">Save</button>
      </form>
    );
  }

});
```

You can even define `getValidationErrorMessage` on the supertype in order to be DRY:

```js
t.Number.getValidationErrorMessage = function (value, path, context) {
  return 'bad number';
};

Age.getValidationErrorMessage = function (value, path, context) {
  return 'bad age, locale: ' + context.locale;
};
```

# Types

Models are defined with [tcomb](https://github.com/gcanti/tcomb). tcomb is a library for Node.js and the browser which allows you to check the types of JavaScript values at runtime with a simple syntax. It's great for Domain Driven Design, for testing, and for adding safety to your internal code.

## Required field

By default fields are required:

```js
var Person = t.struct({
  name: t.String,    // a required string
  surname: t.String  // a required string
});
```

## Optional field

In order to create an optional field, wrap the field type with the `t.maybe` combinator:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String) // an optional string
});
```

The suffix `" (optional)"` is automatically added to optional fields.

You can customise the suffix value, or set a suffix for required fields (see the "Internationalization" section).

## Numbers

In order to create a numeric field, use the `t.Number` type:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number // a numeric field
});
```

tcomb-form will automatically convert numbers to / from strings.

## Refinements

A *predicate* is a function with the following signature:

```
(x: any) => boolean
```

You can refine a type with the `t.refinement(type, predicate)` combinator:

```js
// a type representing positive numbers
var Positive = t.refinement(t.Number, function (n) {
  return n >= 0;
});

var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: Positive
});
```

Refinements allow you to express any custom validation with a simple predicate.

## Booleans

In order to create a boolean field, use the `t.Boolean` type:

```js
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 checkboxes.

## Dates

In order to create a date field, use the `t.Date` type:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number,
  rememberMe: t.Boolean,
  birthDate: t.Date // a date field
});
```

## Enums

In order to create an enum field, use the `t.enums` combinator:

```js
var Gender = t.enums({
  M: 'Male',
  F: 'Female'
});

var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number,
  rememberMe: t.Boolean,
  birthDate: t.Date,
  gender: Gender // enum
});
```

By default enums are displayed as selects.

## Lists

You can handle a list with the `t.list` combinator:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: Positive, // refinement
  rememberMe: t.Boolean,
  birthDate: t.Date,
  gender: Gender,
  tags: t.list(t.String) // a list of strings
});
```

## Nested structures

You can nest lists and structs at an arbitrary level:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var Persons = t.list(Person);

...

<Form
  ref="form"
  type={Persons}
/>
```

# Rendering options

In order to customise the look and feel, use an `options` prop:

```js
<Form type={Model} options={options} />
```

> **Warning**. tcomb-form uses shouldComponentUpdate aggressively. In order to ensure that tcomb-form detect any change to `type`, `options` or `value` props you have to change references:

Example: disable a field based on another field's value

```js
var Type = t.struct({
  disable: t.Boolean, // if true, name field will be disabled
  name: t.String
});

var options = {
  fields: {
    name: {}
  }
};

var App = React.createClass({

  getInitialState() {
    return {
      options: options,
      value: null
    };
  },

  onSubmit(evt) {
    evt.preventDefault();
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  onChange(value) {
    // tcomb immutability helpers
    // https://github.com/gcanti/tcomb/blob/master/GUIDE.md#updating-immutable-instances
    var options = t.update(this.state.options, {
      fields: {
        name: {
          disabled: {'$set': value.disable}
        }
      }
    });
    this.setState({options: options, value: value});
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <Form ref="form"
          type={Type}
          options={this.state.options}
          value={this.state.value}
          onChange={this.onChange}
        />
        <button className="btn btn-primary">Save</button>
      </form>
    );
  }

});
```

## Struct options

### Automatically generated placeholders

In order to generate default placeholders use the option `auto: 'placeholders'`:

```js
var options = {
  auto: 'placeholders'
};

<Form type={Person} options={options} />
```

Or `auto: 'none'` if you don't want neither labels nor placeholders:

```js
var options = {
  auto: 'none'
};
```

### Fields order

You can sort the fields with the `order` option:

```js
var options = {
  order: ['name', 'surname', 'rememberMe', 'gender', 'age', 'email']
};
```

### Legend

You can add a fieldset legend with the `legend` option:

```js
var options = {
  // you can use strings or JSX
  legend: <i>My form legend</i>
};
```

### Help message

You can add an help message with the `help` option:

```js
var options = {
  // you can use strings or JSX
  help: <i>My form help</i>
};
```

### Error message

You can add a custom error message with the `error` options:

```js
var options = {
  // you can use strings or JSX
  error: <i>A custom error message</i>
};
```

`error` can also be a function with the following signature:

```
(value, path, context) => ?(string | ReactElement)
```

- `value` is an object containing the current form value.
- `path` is the path of the value being validated
- `context` is the value of the `context` prop. Also it contains a reference to the component options.

If you want to show the error message onload, add the `hasError` option:

```js
var options = {
  hasError: true,
  error: <i>A custom error message</i>
};<commit_msg>move getValidationErrorMessage docs to error messages section<commit_after>Table of Contents
=================

  * [Get started](#get-started)
    * [Setup](#setup)
    * [Working example](#working-example)
    * [API](#api)
      * [getValue()](#getvalue)
      * [validate()](#validate)
    * [How to](#how-to)
      * [Adding a default value and listening to changes](#adding-a-default-value-and-listening-to-changes)
      * [Accessing fields](#accessing-fields)
      * [Submitting the form](#submitting-the-form)
      * [Customised error messages](#customised-error-messages)
  * [Types](#types)
    * [Required field](#required-field)
    * [Optional field](#optional-field)
    * [Numbers](#numbers)
    * [Refinements](#refinements)
    * [Booleans](#booleans)
    * [Dates](#dates)
    * [Enums](#enums)
    * [Lists](#lists)
    * [Nested structures](#nested-structures)
  * [Rendering options](#rendering-options)
    * [Struct options](#struct-options)
      * [Automatically generated placeholders](#automatically-generated-placeholders)
      * [Fields order](#fields-order)
      * [Legend](#legend)
      * [Help message](#help-message)
      * [Error messages](#error-messages)
      * [Disabled](#disabled)
      * [Fields configuration](#fields-configuration)
      * [Look and feel](#look-and-feel)
    * [List options](#list-options)
      * [Items configuration](#items-configuration)
      * [Internationalization](#internationalization)
      * [Buttons configuration](#buttons-configuration)
    * [Textbox options](#textbox-options)
      * [Type attribute](#type-attribute)
      * [Label](#label)
      * [Attributes and events](#attributes-and-events)
      * [Styling](#styling)
    * [Checkbox options](#checkbox-options)
    * [Select options](#select-options)
      * [Null option](#null-option)
      * [Options order](#options-order)
      * [Custom options](#custom-options)
      * [Render as a radio group](#render-as-a-radio-group)
      * [Multiple select](#multiple-select)
    * [Date options](#date-options)
      * [Fields order](#fields-order-1)
  * [Customizations](#customizations)
    * [Templates](#templates)
    * [Transformers](#transformers)
    * [Custom factories](#custom-factories)
  * [Bootstrap extras](#bootstrap-extras)
    * [Textbox](#textbox)
      * [Addons](#addons)
      * [Size](#size)
    * [Select](#select)
    * [Struct](#struct)
  * [General configuration](#general-configuration)
    * [Changing the default language](#changing-the-default-language)
    * [Changing the default skin](#changing-the-default-skin)

# Get started

## Setup

```sh
$ npm install tcomb-form
```
Note: Use tcomb-form@0.6.x with react@0.13.x. See [#200](https://github.com/gcanti/tcomb-form/issues/200).

## Working example

```js
var React = require('react');
var ReactDOM = require('react/lib/ReactDOM');
var t = require('tcomb-form');
var Form = t.form.Form;

// define your domain model with tcomb
// https://github.com/gcanti/tcomb
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var App = React.createClass({

  save() {
    // call getValue() to get the values of the form
    var value = this.refs.form.getValue();
    // if validation fails, value will be null
    if (value) {
      // value here is an instance of Person
      console.log(value);
    }
  },

  render() {
    return (
      <div>
        <Form
          ref="form"
          type={Person}
        />
        <button onClick={this.save}>Save</button>
      </div>
    );
  }

});

ReactDOM.render(<App />, document.getElementById('app'));
```

> **Note**. Labels are automatically generated.

## API

### `getValue()`

Returns `null` if the validation failed; otherwise returns an instance of your model.

> **Note**. Calling `getValue` will 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](https://github.com/gcanti/tcomb-validation) for a reference documentation).

## How to

### Adding a default value and listening to changes

The `Form` component behaves like a [controlled component](https://facebook.github.io/react/docs/forms.html):

```js
var App = React.createClass({

  getInitialState() {
    return {
      value: {
        name: 'Giulio',
        surname: 'Canti'
      }
    };
  },

  onChange(value) {
    this.setState({value});
  },

  save() {
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {
    return (
      <div>
        <Form
          ref="form"
          type={Person}
          value={this.state.value}
          onChange={this.onChange}
        />
        <button onClick={this.save}>Save</button>
      </div>
    );
  }

});
```

The `onChange` handler has the following signature:

```
(raw: any, path: Array<string | number>, kind?) => 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 change
- `kind` specify the kind of change (when `undefined` means a value change)
  + `'add'` list item added
  + `'remove'` list item removed
  + `'moveUp'` list item moved up
  + `'moveDown'` list item moved down

### Accessing fields

You can get access to a field with the `getComponent(path)` API:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var App = React.createClass({

  onChange(value, path) {
    // validate a field on every change
    this.refs.form.getComponent(path).validate();
  },

  render() {
    return (
      <div>
        <Form ref="form"
          type={Person}
          onChange={this.onChange}
        />
      </div>
    );
  }

});
```

### Submitting the form

The output of the `Form` component is a `fieldset` tag containing your fields. You can submit the form by wrapping the output with a `form` tag:

```js
var App = React.createClass({

  onSubmit(evt) {
    var value = this.refs.form.getValue();
    if (!value) {
      // there are errors, don't send the form
      evt.preventDefault();
    } else {
      // everything ok, let the form fly...
      // ...or handle the values contained in the
      // `value` variable with js
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <Form
          ref="form"
          type={Person}
        />
        <button type="submit">Save</button>
      </form>
    );
  }

});
```

### Customised error messages

See [Error messages](#error-messages) section.

# Types

Models are defined with [tcomb](https://github.com/gcanti/tcomb). tcomb is a library for Node.js and the browser which allows you to check the types of JavaScript values at runtime with a simple syntax. It's great for Domain Driven Design, for testing, and for adding safety to your internal code.

## Required field

By default fields are required:

```js
var Person = t.struct({
  name: t.String,    // a required string
  surname: t.String  // a required string
});
```

## Optional field

In order to create an optional field, wrap the field type with the `t.maybe` combinator:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String) // an optional string
});
```

The suffix `" (optional)"` is automatically added to optional fields.

You can customise the suffix value, or set a suffix for required fields (see the "Internationalization" section).

## Numbers

In order to create a numeric field, use the `t.Number` type:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number // a numeric field
});
```

tcomb-form will automatically convert numbers to / from strings.

## Refinements

A *predicate* is a function with the following signature:

```
(x: any) => boolean
```

You can refine a type with the `t.refinement(type, predicate)` combinator:

```js
// a type representing positive numbers
var Positive = t.refinement(t.Number, function (n) {
  return n >= 0;
});

var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: Positive
});
```

Refinements allow you to express any custom validation with a simple predicate.

## Booleans

In order to create a boolean field, use the `t.Boolean` type:

```js
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 checkboxes.

## Dates

In order to create a date field, use the `t.Date` type:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number,
  rememberMe: t.Boolean,
  birthDate: t.Date // a date field
});
```

## Enums

In order to create an enum field, use the `t.enums` combinator:

```js
var Gender = t.enums({
  M: 'Male',
  F: 'Female'
});

var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: t.Number,
  rememberMe: t.Boolean,
  birthDate: t.Date,
  gender: Gender // enum
});
```

By default enums are displayed as selects.

## Lists

You can handle a list with the `t.list` combinator:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String,
  email: t.maybe(t.String),
  age: Positive, // refinement
  rememberMe: t.Boolean,
  birthDate: t.Date,
  gender: Gender,
  tags: t.list(t.String) // a list of strings
});
```

## Nested structures

You can nest lists and structs at an arbitrary level:

```js
var Person = t.struct({
  name: t.String,
  surname: t.String
});

var Persons = t.list(Person);

...

<Form
  ref="form"
  type={Persons}
/>
```

# Rendering options

In order to customise the look and feel, use an `options` prop:

```js
<Form type={Model} options={options} />
```

> **Warning**. tcomb-form uses shouldComponentUpdate aggressively. In order to ensure that tcomb-form detect any change to `type`, `options` or `value` props you have to change references:

Example: disable a field based on another field's value

```js
var Type = t.struct({
  disable: t.Boolean, // if true, name field will be disabled
  name: t.String
});

var options = {
  fields: {
    name: {}
  }
};

var App = React.createClass({

  getInitialState() {
    return {
      options: options,
      value: null
    };
  },

  onSubmit(evt) {
    evt.preventDefault();
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  onChange(value) {
    // tcomb immutability helpers
    // https://github.com/gcanti/tcomb/blob/master/GUIDE.md#updating-immutable-instances
    var options = t.update(this.state.options, {
      fields: {
        name: {
          disabled: {'$set': value.disable}
        }
      }
    });
    this.setState({options: options, value: value});
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <Form ref="form"
          type={Type}
          options={this.state.options}
          value={this.state.value}
          onChange={this.onChange}
        />
        <button className="btn btn-primary">Save</button>
      </form>
    );
  }

});
```

## Struct options

### Automatically generated placeholders

In order to generate default placeholders use the option `auto: 'placeholders'`:

```js
var options = {
  auto: 'placeholders'
};

<Form type={Person} options={options} />
```

Or `auto: 'none'` if you don't want neither labels nor placeholders:

```js
var options = {
  auto: 'none'
};
```

### Fields order

You can sort the fields with the `order` option:

```js
var options = {
  order: ['name', 'surname', 'rememberMe', 'gender', 'age', 'email']
};
```

### Legend

You can add a fieldset legend with the `legend` option:

```js
var options = {
  // you can use strings or JSX
  legend: <i>My form legend</i>
};
```

### Help message

You can add an help message with the `help` option:

```js
var options = {
  // you can use strings or JSX
  help: <i>My form help</i>
};
```

### Error messages

You can add a custom error message with the `error` option:

```js
var options = {
  error: <i>A custom error message</i> // use strings or JSX
};
```

`error` can also be a function with the following signature:

```
type getValidationErrorMessage = (value, path, context) => ?(string | ReactElement)
```

where

- `value` is the (parsed) current value of the component.
- `path` is the path of the value being validated
- `context` is the value of the `context` prop. Also it contains a reference to the component options.

The value returned by the function will be used as error message.

If you want to show the error message onload, add the `hasError` option:

```js
var options = {
  hasError: true,
  error: <i>A custom error message</i>
};
```

Another (advanced) way to customize the error message is to add a:

```
getValidationErrorMessage(value, path, context) => ?(string | ReactElement)
```

static function to the type, where the arguments are the same as above:

```js
var Age = t.refinement(t.Number, function (n) { return n >= 18; });

// if you define a getValidationErrorMessage function, it will be called on validation errors
Age.getValidationErrorMessage = function (value, path, context) {
  return 'bad age, locale: ' + context.locale;
};

var Schema = t.struct({
  age: Age
});

var App = React.createClass({

  onSubmit(evt) {
    evt.preventDefault();
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <t.form.Form
          ref="form"
          type={Schema}
          context={{locale: 'it-IT'}}
        />
        <button type="submit" className="btn btn-primary">Save</button>
      </form>
    );
  }

});
```

You can even define `getValidationErrorMessage` on the supertype in order to be DRY:

```js
t.Number.getValidationErrorMessage = function (value, path, context) {
  return 'bad number';
};

Age.getValidationErrorMessage = function (value, path, context) {
  return 'bad age, locale: ' + context.locale;
};
{'fraction_non_alphanumeric': 0.14725251380824245, 'fraction_numerical': 0.0010621724968134826, 'mean_word_length': 3.0964467005076144, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 102, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7597207', 'n_tokens_mistral': 9167, 'n_tokens_neox': 8773, 'n_words': 2744}