Field arrays
A somewhat more special case are dynamically generated form fields based on an array. Since adding, removing, swapping and moving items can be a big challenge here, the library provides the FieldArray
component which, in combination with various methods, makes it very easy for you to create such forms.
In our playground you can take a look at a form with a field array and test them out.
Create a field array
Type definition
In the following example we create a field array for a todo form with the following fields:
type TodoForm = {
heading: string;
todos: {
label: string;
deadline: string;
}[];
};
FieldArray component
To dynamically generate the form fields for the todos, you use our FieldArray
component. Then pass the field array items to the loop. These items does not contain the individual fields, but a simple array of unique numbers that React uses to detect when an item is added, moved or removed.
<FieldArray name="todos">
{(fieldArray) =>
fieldArray.items.value.map((item, index) => (
<div key={item}>
<Field name={`todos.${index}.label`}>
{(field, props) => <input {...props} type="text" />}
</Field>
<Field name={`todos.${index}.deadline`}>
{(field, props) => <input {...props} type="date" />}
</Field>
</div>
))
}
</FieldArray>
Validation
As with fields, you can also validate field arrays with the validate
attribute. For example, to limit the length of the array you can use the maxLength
function.
Dot notation
As with nested fields, you use dot notation for the name of each field. It is important that you use the index of the loop to specify the index of the field, so that they are updated when the items are changed.
<Field name={`todos.${index}.label`}>
{(field, props) => <input {...props} type="text" />}
</Field>
Use array methods
Now you can use the insert
, move
, remove
, replace
and swap
method to make changes to the field array. For example, to move the first item forward by two positions, use the move
method. It will automatically take care of rearranging all the fields in between.
move(todoForm, 'todos', { from: 0, to: 2 });
For more details on the other methods, see the API Reference.
Nested field arrays
If you need to nest multiple field arrays, dot notation can get complicated when specifying a field name. To solve this problem, you can use the name of the field array dynamically.
<FieldArray name="todos">
{(fieldArray) =>
fieldArray.items.value.map((item, index) => (
<div key={item}>
<Field name={`${fieldArray.name}.${index}.label`}>
{(field, props) => <input {...props} type="text" />}
</Field>
<Field name={`${fieldArray.name}.${index}.deadline`}>
{(field, props) => <input {...props} type="date" />}
</Field>
</div>
))
}
</FieldArray>
You can nest field arrays as deeply as you like. You will also find a suitable example of this on our playground.