> ## Documentation Index
> Fetch the complete documentation index at: https://docs.frogbot.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Array Field

> Store repeatable rows of recursively configured fields.

The Array field stores an ordered array of objects. Every row uses the same set of fields, and those fields can include other containers.

Arrays suit both simple and complex repeating content, including:

* Image sliders with an [upload field](https://docs.frogbot.ai/fields/upload.md) and caption
* Navigation items with a [relationship field](https://docs.frogbot.ai/fields/relationship.md) and an "open in new tab" checkbox
* Event timeslots with start and end dates, a label, and a related page

To create an Array field, set `type` to `array` and provide its row fields:

```ts theme={"theme":"tokyo-night"}
import type { ArrayField } from 'frogbot'

export const linksField: ArrayField = {
  name: 'links',
  type: 'array',
  labels: {
    singular: 'Link',
    plural: 'Links',
  },
  fields: [
    {
      name: 'label',
      type: 'text',
      required: true,
    },
    {
      name: 'url',
      type: 'text',
      required: true,
      hooks: {
        beforeValidate: [({ req, value }) => {
          req.frogbot.logger.debug('Validating an array row URL')

          return value
        }],
      },
    },
  ],
}
```

Generated records contain an array under the field name. Each row receives an `id` automatically.

## Config options

| Option | Type | Default | Description |
| - | - | - | - |
| `name` | `string` | Required | Property name used in stored records and APIs. See [field names](https://docs.frogbot.ai/fields/overview.md#field-names). |
| `type` | `'array'` | Required | Selects the Array field. |
| `fields` | `Field[]` | Required | Fields included in every row. Each row also gets an `id` unless you define one. |
| `labels` | `{ singular, plural }` | Generated from `name` | Singular and plural row labels. Each accepts the same values as `label`, except `false`. |
| `minRows` | `number` | — | Minimum number of rows when a value is present. |
| `maxRows` | `number` | — | Maximum number of rows when a value is present. |
| `interfaceName` | `string` | — | Name of a reusable top-level generated TypeScript interface for the rows. |
| `dbName` | `string \| ({ tableName }) => string` | Generated from the field path | Table name used by SQL adapters. |
| `label` | `string \| Record<string, string> \| (({ i18n, t }) => string) \| false` | Generated from `name` | Label shown in the admin panel. Use an object keyed by language code for translations, or `false` to hide the label. |
| `required` | `boolean` | `false` | Rejects an empty value in the default validation. |
| `unique` | `boolean` | `false` | MongoDB only: creates a unique index on the whole stored value. SQL adapters ignore it. |
| `index` | `boolean` | `false` | MongoDB only: creates an index on the whole stored value. SQL adapters ignore it. |
| `localized` | `boolean` | `false` | Stores one value per configured locale. Ignored without [localization](https://docs.frogbot.ai/configuration/localization.md) or inside a localized parent. Nested fields do not also need `localized`. |
| `defaultValue` | `object[]` or `({ locale, req, user }) => value` | — | Value used when the field has no value. See [default values](https://docs.frogbot.ai/fields/overview.md#default-values). |
| `validate` | `Validate` | Built-in validator | Replaces the built-in validator. See [validation](https://docs.frogbot.ai/fields/overview.md#validation). |
| `hooks` | `{ beforeValidate, beforeChange, afterChange, afterRead, beforeDuplicate }` | — | Arrays of `FieldHook` functions for each phase. See [field hooks](https://docs.frogbot.ai/hooks/fields.md). |
| `access` | `{ create, read, update }` | Allowed | `FieldAccess` functions for each operation. See [field access control](https://docs.frogbot.ai/access-control/fields.md). |
| `hidden` | `boolean` | `false` | Removes the field from API responses and the admin panel while keeping stored data. |
| `saveToJWT` | `boolean \| string` | `false` | In an auth-enabled collection, copies the value into the user's token. A string sets the token key. See [token data](https://docs.frogbot.ai/authentication/token-data.md). |
| `virtual` | `boolean \| string` | `false` | `true` skips database storage; a string reads a value through a relationship path. Virtual fields are read-only in the admin panel unless `admin.readOnly` is `false`. See [virtual fields](https://docs.frogbot.ai/fields/overview.md#virtual-field-configuration). |
| `disableDuplicate` | `boolean` | `false` | Leaves the value out when a document is duplicated, so the copy uses `defaultValue`. |
| `admin` | `object` | — | Admin-panel options. See [Admin options](#admin-options). |
| `custom` | `Record<string, any>` | — | Server-only metadata for your own code and plugins. Use `admin.custom` for data the browser also needs. |
| `jsonSchema` | `Array<({ jsonSchema }) => JSONSchema4>` | — | Functions that modify the JSON Schema used by [type generation](https://docs.frogbot.ai/typescript/generating-types.md). |

Setting `unique: true` on a field inside an Array creates a collection-wide
database unique index, not uniqueness within one document. Use [custom
validation](https://docs.frogbot.ai/fields/overview.md#validation) on the Array field to reject
duplicate values among its rows.

## Admin options

Array fields inherit the standard [field admin options](https://docs.frogbot.ai/fields/overview.md#admin-options) and add:

| Option | Type | Default | Description |
| - | - | - | - |
| `initCollapsed` | `boolean` | `false` | Collapses each row initially. An editor's saved row state takes precedence. |
| `isSortable` | `boolean` | `true` | Set to `false` to prevent row reordering. |
| `components.RowLabel` | `FrogBotComponent` | Singular label and row number | Component used to label each row, replacing labels such as `Link 01`. |

## Example

This slider requires between two and ten rows and gives every row a title, image, and caption:

```ts theme={"theme":"tokyo-night"}
import type { CollectionConfig } from 'frogbot'

export const Pages: CollectionConfig = {
  slug: 'pages',
  fields: [
    {
      name: 'slider',
      type: 'array',
      label: 'Image slider',
      minRows: 2,
      maxRows: 10,
      interfaceName: 'CardSlider',
      labels: {
        singular: 'Slide',
        plural: 'Slides',
      },
      fields: [
        {
          name: 'title',
          type: 'text',
        },
        {
          name: 'image',
          type: 'upload',
          relationTo: 'files',
          required: true,
        },
        {
          name: 'caption',
          type: 'text',
        },
      ],
    },
  ],
}
```

## Custom components

Use the public field component and FrogBot component type for a custom field wrapper:

```tsx theme={"theme":"tokyo-night"}
import { ArrayField } from '@frogbotai/ui/admin'
import type { ArrayFieldServerProps } from 'frogbot'

export const CustomArrayField = ({
  clientField,
  path,
  permissions,
  schemaPath,
}: ArrayFieldServerProps) => {
  return (
    <ArrayField
      field={clientField}
      path={path}
      permissions={permissions}
      schemaPath={schemaPath}
    />
  )
}
```

A client row label can read the current row without receiving custom props:

```tsx theme={"theme":"tokyo-night"}
'use client'

import { useRowLabel } from '@frogbotai/ui/admin'

export function LinkRowLabel() {
  const { data, rowNumber } = useRowLabel<{ label?: string }>()

  return <span>{data.label || `Link ${rowNumber + 1}`}</span>
}
```

Configure it with `admin.components.RowLabel: '/components/LinkRowLabel#LinkRowLabel'`.

Use `ArrayFieldClientProps` for a client field wrapper. Use `ArrayFieldLabelServerProps` or `ArrayFieldLabelClientProps` to replace only the field label while retaining the default field UI.

```tsx theme={"theme":"tokyo-night"}
'use client'

import { ArrayField } from '@frogbotai/ui/admin'
import type { ArrayFieldClientProps } from 'frogbot'

export const CustomArrayFieldClient = (props: ArrayFieldClientProps) => {
  return <ArrayField {...props} />
}
```

```tsx theme={"theme":"tokyo-night"}
import { FieldLabel } from '@frogbotai/ui/admin'
import type { ArrayFieldLabelServerProps } from 'frogbot'

export const CustomArrayLabel = ({
  clientField,
  path,
}: ArrayFieldLabelServerProps) => {
  return (
    <FieldLabel
      label={clientField?.label || clientField?.name}
      path={path}
      required={clientField?.required}
    />
  )
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.