Form Component Specification

A group of one or more fields, inputs, lists, or other forms. A form results in a JavaScript object.

Implementation

A Form type component is the most complicated component to create. It must do the following:

Rendering Descendants

A form component, when rendering its descendants recursively, must check whether any of them implement this spec, and if so pass additional properties to them. What follows is an explanation of which properties to pass for each component type.

ErrorsBlock (isFormErrors is true)

Input (isFormInput is true)

Form (isForm is true)

Same logic as Input but no isReadOnly prop

FormList (isFormList is true)

Same logic as Input but no isReadOnly prop

Field (isFormField is true)

Properties

ALL properties are optional, but the name property is required on forms that are nested under other forms. The properties listed here are governed by this specification, but components are free to add any number of additional properties as necessary.

errors

PropTypes.arrayOf(PropTypes.shape({
  message: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
}))

Array of error objects for all inputs on this form, as returned from the validator function.

A top-level form would track the errors array in state while nested forms would receive them as props (since validation is done by the highest level form). A form component must handle the case where errors come from props and state by merging the two arrays into one before passing down to descendants.

onChanging

PropTypes.func

As any input anywhere within the form or any of its subforms is changing, the form must call onChanging(newValue, isValid), where newValue is the new value of the form object after the most recent user entry.

onChanging must never be called with the exact same value as the last time it was called.

onChange

PropTypes.func

After any input anywhere within the form or any of its subforms has finished changing, the form must call onChange(newValue, isValid), where newValue is the new value of the form object after the most recent user entry.

onChange must never be called with the exact same value as the last time it was called.

onChange must never be called with a newValue that hasn't been first passed to onChanging. (In other words, consumers can safely use ONLY onChanging without fear of missing any change.)

value

PropTypes.obj

If the form is editing an existing object, it will be provided here. This is a basic JavaScript object which you can expect to match the structure of the object that the form component builds and passes to onChanging, onChange, and onSubmit.

While we recommend that any change to this value should reset the internally stored, work-in-progress value, it is not required. If you update the value in state, you must call onChanging and onChange with the new value.

validateOn

PropTypes.oneOf(['changing', 'changed', 'submit'])

The form must validate prior to calling one of these event functions. Default property value must be "submit". To skip validation, a user would simply not provide a validator function.

validateOnWhenInvalid

PropTypes.oneOf(['changing', 'changed', 'submit'])

This is like validateOn but this value is used instead of validateOn whenever the form is currently invalid. Default property value must be "changing".

validator

PropTypes.func

The form must call validator(value) whenever it needs to validate. It needs to validate whenever validateOn and validateOnWhenInvalid props say that it should.

Static Properties

defaultProps [REQUIRED]

You must include the defaultProps static property, even if it is only an empty object.

isForm [REQUIRED]

Set this to true so that other components know that your component implements the Form specification.

Instance Properties

isDirty() [REQUIRED]

Returns a boolean indicating whether anything has been entered/changed by the user.

getValue() [REQUIRED]

Returns the current value of the form in state

validate() [REQUIRED]

This function must call the validator function and then update the errors tracked in state. It must also return a Promise that resolves with the errors array.

See the ReactoForm Form component's validate function for an example.

submit() [REQUIRED]

This function must call the validator function and then call the onSubmit function.

The object to pass to both functions is the most recent object representing all the form values, which you should be tracking in state. A form object may not be passed to onSubmit unless it has first been passed to both onChanging and onChange.

Expect validator to return an array of error objects a Promise that resolves with an array of error objects, and expect onSubmit to return either undefined or a Promise that resolves if submission was successful. Upon success, the Form component must call resetValue instance function. If onSubmit throws or the returned Promise rejects, do not reset values.

See the ReactoForm Form component's submit function for an example.

resetValue() [REQUIRED]

This function must do the following:

Example

ReactoForm Form