🏁 High performance subscription-based form state management for React
JavaScript
Switch branches/tags
Latest commit b5e4910 Dec 15, 2017 @mark-raymond mark-raymond committed with erikras Fix up for Api -> FormApi rename, and actually expose TypeScript typi…
…ngs (#61)

* Api was renamed for FormApi in final-form.

* Actually expose the TypeScript typings.

README.md

🏁 React Final Form

React Final Form

NPM Version NPM Downloads Build Status codecov.io styled with prettier

βœ… Zero dependencies

βœ… Only peer dependencies: React and 🏁 Final Form

βœ… Opt-in subscriptions - only update on the state you need!

βœ… πŸ’₯ 2.5k gzipped πŸ’₯


Installation

npm install --save react-final-form final-form

or

yarn add react-final-form final-form

Getting Started

🏁 React Final Form is a thin React wrapper for 🏁 Final Form, which is a subscriptions-based form state management library that uses the Observer pattern, so only the components that need updating are re-rendered as the form's state changes. By default, 🏁 React Final Form subscribes to all changes, but if you want to fine tune your form to optimized blazing-fast perfection, you may specify only the form state that you care about for rendering your gorgeous UI.

You can think of it a little like GraphQL's feature of only fetching the data your component needs to render, and nothing else.

Here's what it looks like in your code:

import { Form, Field } from 'react-final-form'

const MyForm = () => (
  <Form
    onSubmit={onSubmit}
    validate={validate}
    render={({ handleSubmit, pristine, invalid }) => (
      <form onSubmit={handleSubmit}>
        <h2>Simple Default Input</h2>
        <div>
          <label>First Name</label>
          <Field name="firstName" component="input" placeholder="First Name" />
        </div>

        <h2>An Arbitrary Reusable Input Component</h2>
        <div>
          <label>Interests</label>
          <Field name="interests" component={InterestPicker} />
        </div>

        <h2>Render Function</h2>
        <Field
          name="bio"
          render={({ input, meta }) => (
            <div>
              <label>Bio</label>
              <textarea {...input} />
              {meta.touched && meta.error && <span>{meta.error}</span>}
            </div>
          )}
        />

        <h2>Render Function as Children</h2>
        <Field name="phone">
          {({ input, meta }) => (
            <div>
              <label>Phone</label>
              <input type="text" {...input} placeholder="Phone" />
              {meta.touched && meta.error && <span>{meta.error}</span>}
            </div>
          )}
        </Field>

        <button type="submit" disabled={pristine || invalid}>
          Submit
        </button>
      </form>
    )}
  />
)

Table of Contents

Examples

Simple Example

Uses the built-in React inputs: input, select, and textarea to build a form with no validation.

Synchronous Record-Level Validation

Introduces a whole-record validation function and demonstrates how to display errors next to fields using child render functions.

Synchronous Field-Level Validation

Introduces field-level validation functions and demonstrates how to display errors next to fields using child render functions.

Asynchronous Field-Level Validation

Demonstrates how field-level validation rules may be asynchronous (return a Promise), as well as how to show a "validating" spinner during the lifetime of the Promise.

Hybrid Synchronous/Asynchronous Record-Level Validation

Demonstrates how you can mix synchronous and asynchronous validation patterns at the record-level, by returning errors synchronously, and falling back to an asynchronous call (by returning a Promise) if sync validation is passing.

Submission Errors

Demonstrates how to return submission errors from failed submits. Notice that the Promise should resolve to the submission error (not reject). Rejection is reserved for communications or server exceptions.

Third Party Components

Demonstrates how easy it is to use third party input components. All the third party component really needs is value and onChange, but more complex components can accept things like errors.

πŸ’₯ Performance Optimization Through Subscriptions πŸ’₯

Demonstrates how, by restricting which parts of form state the form component needs to render, it reduce the number of times the whole form has to rerender. Yet, if some part of form state is needed inside of it, the FormSpy component can be used to attain it.

Independent Error Component

Demonstrates how to make an independent Error component to subscribe to and display the error for any form field.

Loading and Initializing Values

Demonstrates how a form can be initialized, after fetching data, by passing in initialValues as a prop.

Field Arrays

Demostrates how to use the <FieldArray/> component, from react-final-form-arrays, to render an array of inputs, as well as use push, pop, and remove mutations.

Calculated Fields

Demonstrates how to use the final-form-calculate decorator to achieve realtime field calculations through easily defined rules.

Field Warnings

Demonstrates how the power of subscriptions and mutators can be used to build a warning engine: logic to display a message next to each field that is not an error that prevents form submission.

Reusable Field Groups

Demonstrates how fields can be grouped into reusable components.

External Submit

Demonstrates how you can use document.getElementById() or a closure to trigger a submit from outside of the form. For more information, see How can I trigger a submit from outside the form?

Wizard Form

Demonstrates how to use 🏁 React Final Form to create a multi-page "wizard" form, with validation on each page.

Rendering

There are three ways to tell <Form/> and <Field/> what to render:

Method How it is rendered
component prop return React.createElement(this.props.component, props)
render prop return this.props.render(props)
a render function as children return this.props.children(props)

API

The following can be imported from react-final-form.

Field : React.ComponentType<FieldProps>

A component that takes FieldProps and renders an individual field.

Form : React.ComponentType<FormProps>

A component that takes FormProps and surrounds your entire form.

FormSpy : React.ComponentType<FormSpyProps>

A component that takes FormSpyProps and can listen to form state from inside an optimized <Form/>.

version: string

The current used version of 🏁 React Final Form.


Types

FieldProps

These are props that you pass to <Field/>. You must provide one of the ways to render: component, render, or children.

allowNull?: boolean

By default, if your value is null, <Field/> will convert it to '', to ensure controlled inputs. But if you pass true to allowNull, <Field/> will give you a null value. Defaults to false.

children?: ((props: FieldRenderProps) => React.Node) | React.Node

A render function that is given FieldRenderProps, as well as any non-API props passed into the <Field/> component.

component?: React.ComponentType<FieldRenderProps>

A component that is given FieldRenderProps as props, as well as any non-API props passed into the <Field/> component.

name: string

The name of your field.

render?: (props: FieldRenderProps) => React.Node

A render function that is given FieldRenderProps, as well as any non-API props passed into the <Field/> component.

subscription?: FieldSubscription

A FieldSubscription that selects all of the items of FieldState that you wish to update for. If you don't pass a subscription prop, it defaults to all of FieldState.

validate?: (value: ?any, allValues: Object) => ?any

A function that takes the field value, and all the values of the form and returns an error if the value is invalid, or undefined if the value is valid.

value?: any

This is only used for radio buttons! The value of the radio button. The radio button will render as checked if and only if the value given here === the value for the field in the form.

FieldRenderProps

These are the props that <Field/> provides to your render function or component. This object separates out the values and event handlers intended to be given to the input component from the meta data about the field. The input can be destructured directly into an <input/> like so: <input {...props.input}/>. Keep in mind that the values in meta are dependent on you having subscribed to them with the subscription prop

input.name: string

The name of the field.

input.onBlur: (?SyntheticFocusEvent<*>) => void

The onBlur function can take a SyntheticFocusEvent like it would if you had given it directly to an <input/> component, but you can also just call it: props.input.onBlur() to mark the field as blurred (inactive).

input.onChange: (SyntheticInputEvent<*> | any) => void

The onChange function can take a SyntheticInputEvent like it would if you had given it directly to an <input/> component (in which case it will read the value out of event.target.value), but you can also just call it: props.input.onChange(value) to update the value of the field.

input.onFocus: (?SyntheticFocusEvent<*>) => void

The onFocus function can take a SyntheticFocusEvent like it would if you had given it directly to an <input/> component, but you can also just call it: props.input.onFocus() to mark the field as focused (active).

input.value: any

The current value of the field.

meta.active?: boolean

See the 🏁 Final Form docs on active.

meta.data: Object

See the 🏁 Final Form docs on data.

meta.dirty?: boolean

See the 🏁 Final Form docs on dirty.

meta.error?: any

See the 🏁 Final Form docs on error.

meta.initial?: any

See the 🏁 Final Form docs on initial.

meta.invalid?: boolean

See the 🏁 Final Form docs on invalid.

meta.pristine?: boolean

See the 🏁 Final Form docs on pristine.

meta.submitError?: any

See the 🏁 Final Form docs on submitError.

meta.submitFailed?: boolean

See the 🏁 Final Form docs on submitFailed.

meta.submitSucceeded?: boolean

See the 🏁 Final Form docs on submitSucceeded.

meta.touched?: boolean

See the 🏁 Final Form docs on touched.

meta.valid?: boolean

See the 🏁 Final Form docs on valid.

meta.visited?: boolean

See the 🏁 Final Form docs on visited.

FormProps

These are the props that you pass to <Form/>. You must provide one of the ways to render: component, render, or children.

children?: ((props: FormRenderProps) => React.Node) | React.Node

A render function that is given FormRenderProps, as well as any non-API props passed into the <Form/> component.

component?: React.ComponentType<FormRenderProps>

A component that is given FormRenderProps as props, as well as any non-API props passed into the <Form/> component.

debug?: DebugFunction

See the 🏁 Final Form docs on debug.

decorators?: Decorator[]

Decorators to apply to the form.

initialValues?: Object

See the 🏁 Final Form docs on initialValues.

mutators?: { [string]: Mutator }

See the 🏁 Final Form docs on mutators.

onSubmit: (values: Object, callback: ?(errors: ?Object) => void) => ?Object | Promise<?Object> | void

See the 🏁 Final Form docs on onSubmit.

render?: (props: FormRenderProps) => React.Node

A render function that is given FormRenderProps, as well as any non-API props passed into the <Form/> component.

subscription?: FormSubscription

A FormSubscription that selects all of the items of FormState that you wish to update for. If you don't pass a subscription prop, it defaults to all of FormState.

validate?: (values: Object) => Object | Promise<Object>

See the 🏁 Final Form docs on validate.

validateOnBlur?: boolean

See the 🏁 Final Form docs on validateOnBlur.

FormRenderProps

These are the props that <Form/> provides to your render function or component. Keep in mind that the values you receive here are dependent upon which values of FormState you have subscribed to with the subscription prop. This object contains everything in 🏁 Final Form's FormState as well as:

batch: (fn: () => void) => void)

A function that allows batch updates to be done to the form state. See the 🏁 Final Form docs on batch.

blur: (name: string) => void

A function to blur (mark inactive) any field.

change: (name: string, value: any) => void

A function to change the value of any field.

focus: (name: string) => void

A function to focus (mark active) any field.

handleSubmit: (SyntheticEvent<HTMLFormElement>) => void

A function intended for you to give directly to the <form> tag: <form onSubmit={handleSubmit}/>.

initialize: (values: Object) => void

A function that initializes the form values. See the 🏁 Final Form docs on initialize.

mutators?: { [string]: Function }

See the 🏁 Final Form docs on mutators.

reset: () => void

A function that resets the form values to their last initialized values. See the 🏁 Final Form docs on reset.

FormSpyProps

These are the props that you pass to <FormSpy/>. You must provide one of the ways to render: component, render, or children.

children?: ((props: FormSpyRenderProps) => React.Node) | React.Node

A render function that is given FormSpyRenderProps, as well as any non-API props passed into the <FormSpy/> component. Will not be called if an onChange prop is provided.

component?: React.ComponentType<FormSpyRenderProps>

A component that is given FormSpyRenderProps as props, as well as any non-API props passed into the <FormSpy/> component. Will not be called if an onChange prop is provided.

onChange?: (formState: FormState) => void

A change listener that will be called with form state whenever the form state, as subscribed to by the subscription prop, has changed. When an onChange prop is provided, the <FormSpy/> will not render anything.

render?: (props: FormSpyRenderProps) => React.Node

A render function that is given FormSpyRenderProps, as well as any non-API props passed into the <FormSpy/> component. Will not be called if an onChange prop is provided.

subscription?: FormSubscription

A FormSubscription that selects all of the items of FormState that you wish to update for. If you don't pass a subscription prop, it defaults to all of FormState.

FormSpyRenderProps

These are the props that <FormSpy/> provides to your render function or component. These props are of type FormState. Keep in mind that the values you receive here are dependent upon which values of FormState you have subscribed to with the subscription prop.