Skip to content

🏁 High performance subscription-based form state management for React

License

Notifications You must be signed in to change notification settings

eJayYoung/react-final-form

Β 
Β 

Repository files navigation

🏁 React Final Form

React Final Form

Backers on Open Collective Sponsors on Open Collective 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!

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


In the interest of making 🏁 React Final Form the best library it can be, we'd love your thoughts and feedback.

Take a quick survey.


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

Videos

🏁Final Form: Form state management via Observers - HolyJS 2018, Moscow, Russia
🏁 Final Form: Form state management via Observers - HolyJS 2018, Moscow, Russia
Next Generation Forms with 🏁 React Final Form – React Alicante 2018, Alicante, Spain
Next Generation Forms with 🏁 React Final Form – React Alicante 2018, Alicante, Spain

Helper Libraries

Define Form offers alternative typescript bindings for 🏁 Final Form. The key difference is that the form data is now a strongly typed object, rather than an any. This makes the initialValues config option required.

A swap-in replacement for 🏁 React Final Form's <Field> component to provide HTML5 Validation.

A set of adaptor components to facilitate using Material-UI with 🏁 React Final Form.

Examples

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

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

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

Sometimes you want to give your user a chance to make it through a brief invalid value on their way to a valid one, e.g. a date string that needs two numbers on either side of a slash. With a simple delayed rendering component, this becomes easy. Plus, the error will disappear immediately when the user fixes the problem.

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.

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.

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.

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.

Demonstrates how to use Material-UI 3.0 input components.

Demonstrates how, by restricting which parts of form state the form component needs to render, it reduces 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.

Demonstrates how to use JSX generics to strongly type fields, forcing only a component that can accept the type for that field.

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

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

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

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.

Wondering how to get field state from multiple fields at once?

People coming from Redux-Form might be wondering where the equivalent of Redux Form's Fields component is, as a way to get state from several fields at once. The answer is that it's not included in the library because it's so easy to write one recursively composing Field components together.

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

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 (thus it does not prevent form submission).

Demonstrates how fields can be grouped into reusable components.

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?

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

Demonstrates how to use 🏁 React Final Form's parse and format props to control exactly how the data flows from the form state through the input and back to the form state. Notice that you can use parse to "normalize" your values.

Demonstrates how to use a FormSpy component to listen for value changes and automatically submit different values after a debounce period.

Demonstrates how to use a FormSpy component to listen for value changes and automatically submit different values after a debounce period, but only does the debounce for certain specified fields, in this case, all the text fields.

Demonstrates how to use a FormSpy component to listen for values and active field changes to automatically submit values when fields are blurred.

Demonstrates how incredibly extensible FormSpy, the setFieldData mutator, and render props are by implementing a custom validation engine completely apart from the built-in validation in 🏁 Final Form, thus allowing for special behaviors, like only validating a single field when that field is blurred.

Demonstrates how to make a wrapper component to handle loading, normalization of data, saving, and reinitializing of the form, to maintain pristine/dirty state with saved data.

Demonstrates how to use a 🏎️ Downshift type-ahead component as an input.

The only reason to keep your 🏁 Final Form form data in Redux is if you need to be able to read it from outside your form. This example demonstrates how to use a FormSpy to keep a copy of your form data in the Redux store. Note that the canonical authoritative version of the data still lives in 🏁 Final Form. If you need to mutate your data via dispatching Redux actions, you should probably use Redux Form.

Sometimes you might want to conditionally show or hide some parts of your form depending on values the user has already provided for other form inputs. 🏁 React Final Form makes that very easy to do by creating a Condition component out of a Field component.

By wrapping a stateful ExternalModificationDetector component in a Field component, we can listen for changes to a field's value, and by knowing whether or not the field is active, deduce when a field's value changes due to external influences.

Demonstrates how to incorporate the 🏁 Final Form Focus 🧐 decorator to provide this functionality out of the box.

Demonstrates how to make an awesome credit card UX using React Credit Cards.

Want to use redux-saga or redux-observable to manage your form submissions? Now you can, using react-redux-promise-listener to convert your dispatched Redux actions into the Promise that 🏁 React Final Form is expecting for its onSubmit function.

What if you could define rules to update fields when other fields change as components? This example explores such possibilities. There's also a Medium post about writing it, and creating a companion library, react-final-form-listeners.

Demonstrates how to use the library format-string-by-pattern to create input masks for your 🏁 React Final Form fields.

Demonstrates creating an AsyncTypeahead to select github users, while storing the search results in the redux store and the form state (selected github users) via react-final-form. Also makes use of the setFieldData mutator.

Demonstrates how to use the formatOnBlur prop to postpone the formatting of a form field value until the field loses focus. Very useful for formatting numbers, like currencies.

Demonstrates how to use the Smooth-UI styling library to make your forms look fabulous! All you really need is a higher order component that adapts The 🍭 Smooth-UI form controls to work with 🏁 React Final Form.

CLI Example 🀯

Yes! You can actually use 🏁 React Final Form in a command line interface! Thanks to packages like Ink and Pastel, the power of 🏁 Final Form's form state management works just fine on the command line.

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/>.

useForm

The useForm hook plucks the FormApi out of the React context for you. It will throw an exception if you try to use it outside of a <Form> component.

useField

The useField hook takes two parameters, the first is the name of the field, and the second is an optional object that looks just like FieldProps, except without the name. It returns an object just like FieldRenderProps.

useField is used internally inside Field.

useFormState

The useFormState hook takes one optional parameter, which matches the exact shape of FormSpyProps. It returns a FormSpyRenderProps.

useFormState is used internally inside FormSpy.

version: string

The current used version of 🏁 React Final Form.

withTypes<T>: () => { Form<T>, FormSpy<T> }

Provides versions of Form and FormSpy that will have strongly typed values.


Types

FieldProps

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

afterSubmit?: () => void

A callback to notify fields after submission has completed successfully.

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.

beforeSubmit?: () => void | false

A function to call just before calling onSubmit. If beforeSubmit returns false, the submission will be aborted. If one of your fields returns false on beforeSubmit, other fields may not have their beforeSubmit called, as the submission is aborted on the first one that returns 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> | string

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

defaultValue?: any

⚠️ You probably want initialValue! ⚠️

Before using this prop, read and understand the 🏁 Final Form documentation on initialValue and defaultValue!

format?: ((value: any, name: string) => any)

A function that takes the value from the form values and the name of the field and formats the value to give to the input. Common use cases include converting javascript Date values into a localized date string. Almost always used in conjunction with parse.

Note: If you would like to disable the default behavior of converting undefined to '', you can pass an identity function, v => v, to format. If you do this, making sure your inputs are "controlled" is up to you.

formatOnBlur?: boolean

If true, the format function will only be called when the field is blurred. If false, format will be called on every render. Defaults to false.

initialValue?: any

See the 🏁 Final Form docs on initialValue

isEqual?: (a: any, b: any) => boolean

See the 🏁 Final Form docs on isEqual.

name: string

The name of your field. Field values may be deeply nested using dot-and-bracket syntax. Learn more about Field Names.

parse?: ((value: any, name: string) => any)

A function that takes the value from the input and name of the field and converts the value into the value you want stored as this field's value in the form. Common usecases include converting strings into Numbers or parsing localized dates into actual javascript Date objects. Almost always used in conjuction with format.

Note: If would like to override the default behavior of converting '' to undefined, you can pass an identity function, v => v, to parse, thus allowing you to have form values of ''.

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

A render function that is given FieldRenderProps, children prop, 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, meta: ?FieldState) => ?any

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

⚠️ IMPORTANT ⚠️ – By default, in order to allow inline fat-arrow validation functions, the field will not rerender if you change your validation function to an alternate function that has a different behavior. If you need your field to rerender with a new validation function, you will need to update another prop on the Field, such as key.

validateFields?: string[]

See the 🏁 Final Form docs on validateFields.

⚠️ IMPORTANT ⚠️ – By default, in order to allow inline [] syntax, the field will not rerender if you change your validateFields prop changes. If you need your field to rerender with a new validateFields setting, you will need to update another prop on the Field, such as key.

value?: any

This is only used for checkboxes and radio buttons!

  • 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.
  • Checkboxes:
    • value is specified: the checkbox will be checked if the value given in value is contained in the array that is the value for the field for the form. Checking the box will add the value to the array, and unchecking the checkbox will remove the value from the array.
    • no value is specified: the checkbox will be checked if the value is truthy. Checking the box will set the value to true, and unchecking the checkbox will set the value to false.

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.modified?: boolean

See the 🏁 Final Form docs on modified.

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.submitting?: boolean

See the 🏁 Final Form docs on submitting.

meta.touched?: boolean

See the 🏁 Final Form docs on touched.

meta.valid?: boolean

See the 🏁 Final Form docs on valid.

meta.validating?: boolean

See the 🏁 Final Form docs on validating.

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.

initialValuesEqual?: (?Object, ?Object) => boolean

A predicate to determine whether or not the initialValues prop has changed. Useful for passing in a "deep equals" function if you need to. Defaults to "shallow equals".

keepDirtyOnReinitialize?: boolean

See the 🏁 Final Form docs on keepDirtyOnReinitialize.

mutators?: { [string]: Mutator }

See the 🏁 Final Form docs on mutators.

onSubmit: (values: Object, form: FormApi, 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:

form: FormApi

The 🏁 Final Form FormApi.

handleSubmit: (?SyntheticEvent<HTMLFormElement>) => ?Promise<?Object>

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

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. Also included will be many of the same props provided to FormRenderProps:

form: FormApi

The 🏁 Final Form FormApi.

See the 🏁 Final Form docs on mutators.

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! πŸ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

About

🏁 High performance subscription-based form state management for React

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 96.5%
  • TypeScript 3.5%