Field
The Field Component renders a form control and handles input value updates and validations.
Changes to the <Field>
value are automatically propagated back up to the containing Form
Component.
Overview
In the simplest cases <Field>
s provide a light abstraction over normal input components. Fields
shouls provide a name
mapping the input to a branch of the central form data.
Providing values and onChange handlers is taken take care of, as well as basic
value coalescing for multiple selects and checkbox groups.
You can manually control the type and sort of input via the as
prop (for textareas and selects),
and the type
prop for inputs
same as with plain HTML inputs. Fields always
provide value
and onChange
props to their inputs.
Checkbox and Radios
Create a unified set of checkbox/radio input's that map to a single form field
by using multiple <Field>
s with the same name
.
Use groups of checkboxes to represent list values. React Formal will intelligently
insert or remove items if the current field value is an array
or, absent a
value, the schema for the field is a yup.array()
.
Custom components
Fields are not limited to native input components. You can pass any component
type to as
. The only required interface a component needs to respect is the
value
/onChange
pattern for controlled fields.
For a better typed experience with TypeScript, consider using the render prop API instead.
import Form from "../components/FormWithResult";import DropdownList from "react-widgets/lib/DropdownList";<Form defaultValue={{ color: "red" }}> <label> Favorite Colors <Form.Field name="color"> {props => ( <DropdownList data={["Red", "Yellow", "Blue", "Other"]} {...props} /> )} </Form.Field> </label></Form>;
In addition to injecting <Field>
components with events and the field value
, a
special prop called meta
is also provided to all Field renderer components. meta
contains helpful context and methods for doing manual field operations.
interface FieldMeta { value: any; // the Field Value valid: boolean; // Whether the field is currently valid invalid: boolean; // inverse of valid touched: boolean: // whether the field has been touched yet errors: Errors; // the errors for this field schema?: YupSchema; // the schema for this field context?: Record<string, any>; // a yup context object nativeTagName: 'input' | 'select'; // The inferred native HTML element. nativeType: string; // The inferred HTML input type, only valid for 'input's // onError allows manually _replacing_ errors for the Field `name` // any existing errors for this path will be removed first onError(errors: Errors): void // The same callback passed to field components // for updating (and validating) a field value onChange(nextFieldValue: any): void}
Validation
Field validation is automatically enabled for Fields with cooresponding Form schema.
Fields inject onChange
and onBlur
handlers to fire a validation.
Field validation is debounced (see Form delay) to reduce unnecessary
checks while the user is still engaging with the input. Validation can be
disabled per field with the noValidate
prop.
Trigger Events
Validation trigger events can be finely controlled via the validateOn
prop.
Events control which handlers <Field>
passes to the input it renders. Multiple triggers
can be configured using an object configuration.
For more complex situations validateOn
accepts a function that is based the meta
for the field
and can conditionally return events based on context.
Preset Strategies
As a convenience React Formal exports a few common trigger configurations you can mix and match if that is helpful.
import { ValidateStrategies } from "react-formal";const { Change, Blur, ChangeAndBlur, BlurThenChangeAndBlur} = ValidateStrategies;<Form schema={schema}> <label> Email <Form.Field name="email" validateOn={Blur} /> </label> <Form.Message for="email" className="error" /></Form>;
There is nothing special about these strategies, and you can roll your own easily. These are provied as a small convenience.
API
import Form from 'react-formal';
const Field = Form.Field
as
The Component Input the form should render. You can sepcify a native element such as 'input' or 'select'
or provide a Component type class directly. When no type is provided the Field will attempt determine
the correct input from the Field's schema. A Field corresponding to a yup.number()
will render a type='number'
etc.
Custom Inputs should comply with the basic input api contract: set a value via a value
prop and
broadcast changes to that value via an onChange
handler.
children
When children is the traditional react element or nodes, they are
passed through as-is to the Field type
component.
<Field type='select'> <option>red</option> <option>red</option></Field>
When children
is a function, its called with the processed field
props and field meta.
Tip: you can pass onChange
and onBlur
handlers
to the <Field>
component and it will handle merging them with its own injected
handlers.
<Field name='birthDate'> {(props, meta) => <DataProvider> <Input {...props} /> </DataProvider> }</Field>
className
errorClass
The css class added to the Field Input when it fails validation
exclusive
Indicates whether child paths of the current Field affect the active state of the field.
'names' - 'first' - 'last'
Are all considered "part" of a field named 'names'
by default. Does not
affect which paths are validated, only whether meta.valid
considers child
paths for its state.
injectMeta
Instruct the field to not inject the meta
prop into the input,
defaults to true
when as
is a non DOM component
mapFromValue
Customize how the Field value maps to the overall Form value
.
mapFromValue
can be a a string property name or a function that returns a
value for name
'd path, allowing you to set commuted values from the Field.
<Form.Field name='name' mapFromValue={fieldValue => `${fieldValue.first} ${fieldValue.last}`}/>
You can also provide an object hash, mapping paths of the Form value
to fields in the field value using a string field name, or a function accessor.
mapToValue
Map the Form value to the Field value. By default
the name
of the Field is used to extract the relevant
property from the Form value.
<Form.Field name='location' type="dropdownlist" mapToValue={model=> pick(model, 'location', 'locationId')}/>
namerequired
The Field name, which should be path corresponding to a specific form value
path.
// given the form valuevalue = { name: { first: '' } languages: ['english', 'spanish']}// the path "name.first" would update the "first" property of the form value<Form.Field name='name.first' />// use indexes for paths that cross arrays<Form.Field name='languages[0]' />
noValidate
Disables validation for the Field.
onBlur
A local onBlur handler, will be merged with the injected onBlur
onChange
A local onChange handler, will be merged with the injected onChange
type
An HTML input type attribute
validateOn
Configure whether validation occur: onChange, onBlur, or both
You can also specify a function that receives the Field meta
object and returns a configuration map
in order to change validation strategies based on validity or other metadata.
validates
Tells the Field to trigger validation for specific paths.
Useful when used in conjuction with a mapFromValue
hash that updates more than one value, or
if you want to trigger validation for the parent path as well.
NOTE! This overrides the default behavior of validating the field itself by
name
, include thename
if you want the field to validate itself.
<Form.Field name='name.first' validates="name.last" /><Form.Field name='name' validates={['name', 'surname']} />
value
A value to pass to checkboxs/radios/boolean inputs