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