Form Wire
Guides

Arrays

String arrays and object arrays with dynamic controls

Form Wire supports two types of array fields: string arrays and object arrays.

String Arrays

const schema = z.object({
  tags: z.string().min(1).array().min(1),
});

Renders as a dynamic list of text inputs with:

  • Add button to append a new empty input
  • Remove button per item
  • Move up / Move down buttons per item

Configure labels:

fields: {
  tags: {
    label: "Tags",
    array: {
      addLabel: "Add tag",
      removeLabel: "Remove",
      moveUpLabel: "Up",
      moveDownLabel: "Down",
      itemLabel: "Tag",
    },
  },
}

itemLabel can be a string or a function:

itemLabel: (index) => `Tag ${index + 1}`

Object Arrays

const schema = z.object({
  users: z.object({
    name: z.string().min(1),
    email: z.email(),
  }).array(),
});

Each item renders as a <fieldset> with all its nested fields. The same add/remove/reorder controls apply.

Configure per-item fields in the schema — they use the same config system as top-level fields.

Nested Object Arrays

const schema = z.object({
  team: z.object({
    name: z.string(),
    users: z.object({
      name: z.string(),
      email: z.email(),
    }).array(),
  }),
});

Nested arrays work identically — they render inside their parent fieldset group.

Read-Only and Disabled Arrays

When an array field is read-only or disabled, the add/remove/reorder controls are hidden automatically.

Array Field Values

Array values are submitted as repeated form entries with the same name:

<input name="tags" value="react" />
<input name="tags" value="zod" />

Form Wire parses these back into a string[] automatically.

Object Array Naming

Object array items use bracket-style naming:

<input name="users[0].name" value="Ada" />
<input name="users[0].email" value="ada@form.dev" />
<input name="users[1].name" value="Grace" />

Form Wire handles the serialization and parsing transparently.

On this page