0
# Field Component
1
2
Individual field components with subscription-based state management, validation, formatting, and parsing capabilities.
3
4
## Capabilities
5
6
### Field Component
7
8
React component for individual form fields that connects to form state and provides input props and field metadata.
9
10
```typescript { .api }
11
/**
12
* Form field component with subscription-based state management
13
* @param props - Field configuration and render props
14
* @returns React element for the field
15
*/
16
const Field: <
17
FieldValue = any,
18
T extends HTMLElement = HTMLElement,
19
FormValues = Record<string, any>
20
>(
21
props: FieldProps<FieldValue, T, FormValues>
22
) => React.ReactElement;
23
24
interface FieldProps<
25
FieldValue = any,
26
T extends HTMLElement = HTMLElement,
27
FormValues = Record<string, any>
28
> extends UseFieldConfig,
29
Omit<RenderableProps<FieldRenderProps<FieldValue, T>>, "children"> {
30
/** Field name (required) */
31
name: string;
32
/** Render function or React node */
33
children?: RenderableProps<FieldRenderProps<FieldValue, T>>["children"];
34
/** Additional HTML element props */
35
[key: string]: any;
36
}
37
38
interface FieldRenderProps<
39
FieldValue = any,
40
T extends HTMLElement = HTMLElement,
41
FormValues = any
42
> {
43
/** Input props to spread on form elements */
44
input: FieldInputProps<FieldValue, T>;
45
/** Field metadata and state information */
46
meta: FieldMeta;
47
}
48
49
interface FieldInputProps<
50
FieldValue = any,
51
T extends HTMLElement = HTMLElement
52
> {
53
/** Field name */
54
name: string;
55
/** Blur event handler */
56
onBlur: (event?: React.FocusEvent<T>) => void;
57
/** Change event handler */
58
onChange: (event: React.ChangeEvent<T> | any) => void;
59
/** Focus event handler */
60
onFocus: (event?: React.FocusEvent<T>) => void;
61
/** Current field value */
62
value: FieldValue;
63
/** Checkbox/radio checked state */
64
checked?: boolean;
65
/** Multiple selection support */
66
multiple?: boolean;
67
/** Input type attribute */
68
type?: string;
69
}
70
71
interface FieldMeta {
72
/** Whether field is currently focused */
73
active?: boolean;
74
/** Custom field data */
75
data?: Record<string, any>;
76
/** Whether field value differs from initial */
77
dirty?: boolean;
78
/** Whether field is dirty since last submit */
79
dirtySinceLastSubmit?: boolean;
80
/** Current field validation error */
81
error?: any;
82
/** Initial field value */
83
initial?: any;
84
/** Whether field has validation errors */
85
invalid?: boolean;
86
/** Array length for array fields */
87
length?: number;
88
/** Whether field was ever modified */
89
modified?: boolean;
90
/** Whether field was modified since last submit */
91
modifiedSinceLastSubmit?: boolean;
92
/** Whether field value equals initial value */
93
pristine?: boolean;
94
/** Submission error for this field */
95
submitError?: any;
96
/** Whether last submission failed */
97
submitFailed?: boolean;
98
/** Whether last submission succeeded */
99
submitSucceeded?: boolean;
100
/** Whether form is currently submitting */
101
submitting?: boolean;
102
/** Whether field was ever focused */
103
touched?: boolean;
104
/** Whether field passes validation */
105
valid?: boolean;
106
/** Whether field is currently being validated */
107
validating?: boolean;
108
/** Whether field was ever visited (focused then blurred) */
109
visited?: boolean;
110
}
111
```
112
113
**Usage Examples:**
114
115
```typescript
116
import React from "react";
117
import { Form, Field } from "react-final-form";
118
119
// Basic text input field
120
function BasicField() {
121
return (
122
<Field name="firstName">
123
{({ input, meta }) => (
124
<div>
125
<label>First Name</label>
126
<input {...input} type="text" placeholder="First Name" />
127
{meta.error && meta.touched && <span>{meta.error}</span>}
128
</div>
129
)}
130
</Field>
131
);
132
}
133
134
// Field with validation
135
function ValidatedField() {
136
const required = (value: any) => (value ? undefined : "Required");
137
138
return (
139
<Field name="email" validate={required}>
140
{({ input, meta }) => (
141
<div>
142
<label>Email</label>
143
<input {...input} type="email" placeholder="Email" />
144
{meta.error && meta.touched && (
145
<span className="error">{meta.error}</span>
146
)}
147
{meta.validating && <span>Validating...</span>}
148
</div>
149
)}
150
</Field>
151
);
152
}
153
154
// Select field
155
function SelectField() {
156
return (
157
<Field name="country">
158
{({ input, meta }) => (
159
<div>
160
<label>Country</label>
161
<select {...input}>
162
<option value="">Select a country</option>
163
<option value="us">United States</option>
164
<option value="uk">United Kingdom</option>
165
<option value="ca">Canada</option>
166
</select>
167
{meta.error && meta.touched && <span>{meta.error}</span>}
168
</div>
169
)}
170
</Field>
171
);
172
}
173
174
// Checkbox field
175
function CheckboxField() {
176
return (
177
<Field name="subscribe" type="checkbox">
178
{({ input, meta }) => (
179
<div>
180
<label>
181
<input {...input} type="checkbox" />
182
Subscribe to newsletter
183
</label>
184
</div>
185
)}
186
</Field>
187
);
188
}
189
```
190
191
### Field Configuration
192
193
Fields support extensive configuration options for validation, formatting, parsing, and behavior customization.
194
195
```typescript { .api }
196
interface UseFieldConfig extends UseFieldAutoConfig {
197
/** Field state subscription configuration */
198
subscription?: FieldSubscription;
199
}
200
201
interface UseFieldAutoConfig {
202
/** Callback after successful submission */
203
afterSubmit?: () => void;
204
/** Allow null values instead of undefined */
205
allowNull?: boolean;
206
/** Callback before submission, return false to prevent */
207
beforeSubmit?: () => void | false;
208
/** Component to render (alternative to render prop) */
209
component?: React.ComponentType<any> | SupportedInputs;
210
/** Custom data attached to field */
211
data?: Record<string, any>;
212
/** Default value when field is undefined */
213
defaultValue?: any;
214
/** Function to format value for display */
215
format?: (value: any, name: string) => any;
216
/** Whether to format on blur instead of every change */
217
formatOnBlur?: boolean;
218
/** Initial field value */
219
initialValue?: any;
220
/** Custom equality function for value comparison */
221
isEqual?: (a: any, b: any) => boolean;
222
/** Multiple selection support */
223
multiple?: boolean;
224
/** Function to parse display value to stored value */
225
parse?: (value: any, name: string) => any;
226
/** Input type attribute */
227
type?: string;
228
/** Field validation function */
229
validate?: FieldValidator<any>;
230
/** Other fields to validate when this field changes */
231
validateFields?: string[];
232
/** Controlled field value */
233
value?: any;
234
}
235
236
interface FieldSubscription {
237
active?: boolean;
238
data?: boolean;
239
dirty?: boolean;
240
dirtySinceLastSubmit?: boolean;
241
error?: boolean;
242
initial?: boolean;
243
invalid?: boolean;
244
length?: boolean;
245
modified?: boolean;
246
modifiedSinceLastSubmit?: boolean;
247
pristine?: boolean;
248
submitError?: boolean;
249
submitFailed?: boolean;
250
submitSucceeded?: boolean;
251
submitting?: boolean;
252
touched?: boolean;
253
valid?: boolean;
254
validating?: boolean;
255
value?: boolean;
256
visited?: boolean;
257
}
258
259
type FieldValidator<FieldValue> = (
260
value: FieldValue,
261
allValues: Record<string, any>,
262
meta?: FieldState<FieldValue>
263
) => any | Promise<any>;
264
265
type SupportedInputs = "input" | "select" | "textarea";
266
```
267
268
**Usage Examples:**
269
270
```typescript
271
// Field with formatting and parsing
272
function CurrencyField() {
273
const format = (value: number) => {
274
if (value === undefined) return "";
275
return new Intl.NumberFormat("en-US", {
276
style: "currency",
277
currency: "USD",
278
}).format(value);
279
};
280
281
const parse = (value: string) => {
282
const number = parseFloat(value.replace(/[^0-9.-]/g, ""));
283
return isNaN(number) ? undefined : number;
284
};
285
286
return (
287
<Field
288
name="price"
289
format={format}
290
parse={parse}
291
>
292
{({ input, meta }) => (
293
<div>
294
<label>Price</label>
295
<input {...input} type="text" placeholder="$0.00" />
296
{meta.error && meta.touched && <span>{meta.error}</span>}
297
</div>
298
)}
299
</Field>
300
);
301
}
302
303
// Field with custom validation
304
function EmailField() {
305
const validateEmail = (value: string) => {
306
if (!value) return "Required";
307
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
308
return "Invalid email address";
309
}
310
return undefined;
311
};
312
313
return (
314
<Field
315
name="email"
316
validate={validateEmail}
317
subscription={{ value: true, error: true, touched: true }}
318
>
319
{({ input, meta }) => (
320
<div>
321
<label>Email</label>
322
<input {...input} type="email" />
323
{meta.error && meta.touched && <span>{meta.error}</span>}
324
</div>
325
)}
326
</Field>
327
);
328
}
329
330
// Field with component prop
331
function ComponentField() {
332
const TextInput = ({ input, meta, ...props }: any) => (
333
<div>
334
<input {...input} {...props} />
335
{meta.error && meta.touched && <span>{meta.error}</span>}
336
</div>
337
);
338
339
return (
340
<Field
341
name="description"
342
component={TextInput}
343
type="text"
344
placeholder="Enter description"
345
/>
346
);
347
}
348
```
349
350
### Field State Management
351
352
Fields maintain comprehensive state information and support advanced state management features.
353
354
```typescript { .api }
355
interface FieldState<FieldValue = any> {
356
/** Whether field is currently active (focused) */
357
active?: boolean;
358
/** Custom data attached to field */
359
data?: Record<string, any>;
360
/** Whether field value differs from initial */
361
dirty?: boolean;
362
/** Whether field is dirty since last submit */
363
dirtySinceLastSubmit?: boolean;
364
/** Current validation error */
365
error?: any;
366
/** Initial field value */
367
initial?: FieldValue;
368
/** Whether field has validation errors */
369
invalid?: boolean;
370
/** Array length for array fields */
371
length?: number;
372
/** Whether field was ever modified */
373
modified?: boolean;
374
/** Whether field was modified since last submit */
375
modifiedSinceLastSubmit?: boolean;
376
/** Whether field value equals initial value */
377
pristine?: boolean;
378
/** Submission error for this field */
379
submitError?: any;
380
/** Whether last submission failed */
381
submitFailed?: boolean;
382
/** Whether last submission succeeded */
383
submitSucceeded?: boolean;
384
/** Whether form is currently submitting */
385
submitting?: boolean;
386
/** Whether field was ever focused */
387
touched?: boolean;
388
/** Whether field passes validation */
389
valid?: boolean;
390
/** Whether field is currently being validated */
391
validating?: boolean;
392
/** Current field value */
393
value?: FieldValue;
394
/** Whether field was ever visited (focused then blurred) */
395
visited?: boolean;
396
}
397
```
398
399
### Array Fields
400
401
Fields support array operations for dynamic field lists and complex data structures.
402
403
```typescript { .api }
404
/**
405
* Array field operations available through field meta when length > 0
406
*/
407
interface ArrayFieldMeta extends FieldMeta {
408
/** Number of items in the array */
409
length?: number;
410
}
411
```
412
413
**Usage Example:**
414
415
```typescript
416
function ArrayField() {
417
return (
418
<Field name="items">
419
{({ input, meta }) => (
420
<div>
421
<label>Items ({meta.length || 0})</label>
422
{/* Array field rendering logic */}
423
{meta.length && <div>Array has {meta.length} items</div>}
424
</div>
425
)}
426
</Field>
427
);
428
}
429
```