Skip to content

List Field

The List field type allows users to create and manage lists of items within the CMS entry form. It supports various configurations for defining the structure and type of items in the list, either as a simple array or as a list of complex objects.

User Interface

Editor

The List field type has four different UI modes, depending on the configuration:

  • Complex list field:
    • With the field option: A single subfield editor is shown for each item in the list.
    • With the fields option: A group of subfield editors is shown for each item in the list.
    • With the types option: A type selector is shown for each item, along with the corresponding subfield editors. This configuration is called a variable type list. It’s useful for creating flexible content structures like page builders.
  • Simple list field:
    • Without the field, fields or types option: A simple multiline text area is shown for editing string values. This allows users to enter list items separated by new lines, where spaces and commas are treated as part of the item values instead of delimiters.

With a complex list field:

  • Each item in the list can be expanded or collapsed to show or hide its subfields.
  • Each item comes with a menu that allows users to duplicate the item, insert a new item above/below it, or remove it.
  • Users can expand or collapse the entire list using the Expand All and Collapse All buttons.

Future Plans

The UI will be improved in the future to support additional features like drag-and-drop reordering, inline editing, and better handling of large lists.

Preview

A list view displaying all items in the list. For complex list fields, grouped subfield values are shown for each item. For simple list fields, a bulleted list of string values is displayed.

Data Type

An array. The elements can be strings or objects, depending on the configuration.

If the required option is set to false and the field is left empty, the value will be an empty array.

Data Validation

  • If the required option is set to true, the list must contain at least one item.
  • If the min and/or max options are specified, the number of items in the list must be within the defined limits.
  • Each item in the list is validated according to the subfield definitions, if applicable.

Options

In addition to the common field options, the List field supports the following options:

Required Options

widget

  • Type: string
  • Default: string

Must be set to list to use the List field type.

General Options

default

Subfield Definition

These options are mutually exclusive; you can only use one of them at a time:

field

fields

types

  • Type: array of variable type definitions

Each type definition is an object with the following properties:

  • name (string, required): The unique identifier for the type.
  • label (string, required): The display label for the type.
  • widget (string, optional): The field type for this type. It must be object if not omitted. Other field types are invalid.
  • fields (array of field definitions, optional): The subfields for this type.

Subfield Options

These options are effective only when the field, fields, or types option is used:

root

  • Type: boolean
  • Default: false

Whether to store the list at the root level of the output file, without a parent key. This is useful for creating top-level lists in files.

The root option is ignored in the following cases:

  • The file or singleton contains multiple fields. You can still have subfields under the List field.
  • The file format is TOML, because TOML doesn’t support top-level arrays.

See the Top-Level List example below for details.

label_singular

  • Type: string
  • Default: The value of the label option

A label used for singular items in the list, e.g., "Member" for a list labeled "Members". It will be displayed on the Add button and in other relevant places in the UI.

summary

  • Type: string
  • Default: ""

A template string used to generate a summary for each item in the collapsed view. It can include subfield values using the {{subfield_name}} syntax. String transformations can be applied in this option. If omitted, the summary will be automatically generated based on the first textual subfield found.

See the Using Summary and Thumbnail example below for details.

thumbnail

  • Type: string
  • Default: ""

An Image subfield name to be used as the thumbnail for each list item in the collapsed view, if applicable. If omitted, no thumbnail will be displayed.

See the Using Summary and Thumbnail example below for details.

collapsed

  • Type: boolean or auto
  • Default: false

Whether each item is initially collapsed in the UI. If set to auto, the UI is collapsed if an item has any filled subfields and expanded if all the subfields are empty.

minimize_collapsed

  • Type: boolean or auto
  • Default: false

Whether the entire list is minimized when collapsed. If set to auto, the list is minimized if any item has any filled subfields and expanded if all items are empty.

allow_add

  • Type: boolean
  • Default: true

Whether to allow adding new items to the list. If set to false, the Add button will be hidden.

allow_remove

  • Type: boolean
  • Default: true

Whether to allow removing items from the list. If set to false, the Remove button will be hidden.

allow_reorder

  • Type: boolean
  • Default: true

Whether to allow reordering of items in the list with an arrow handle or drag-and-drop. If set to false, the reorder handles will be hidden.

min

  • Type: integer
  • Default: 0

The minimum number of items required in the list. If the number of items is below this value, a validation error will be shown.

max

  • Type: integer
  • Default: Infinity

The maximum number of items allowed in the list. If the number of items exceeds this value, a validation error will be shown.

add_to_top

  • Type: boolean
  • Default: false

Whether to add new items to the top of the list instead of the bottom. If set to true, the Add button will appear at the top of the list.

typeKey

  • Type: string
  • Default: type

This option is effective only when the types option is used. It allows you to customize the name of the field that indicates the type of each item in the list. See the Variable Type example below for details.

You cannot use a key that conflicts with any of the subfield names defined in the object.

TIP

Unlike most of other config options, typeKey is camelCased.

Examples

Simple List

Configuration example:

yaml
- name: tags
  label: Tags
  widget: list
toml
[[fields]]
name = "tags"
label = "Tags"
widget = "list"
json
{
  "name": "tags",
  "label": "Tags",
  "widget": "list"
}
js
{
  name: "tags",
  label: "Tags",
  widget: "list",
}

Output example:

yaml
tags:
  - travel
  - photography
  - food
toml
tags = ["travel", "photography", "food"]
json
{
  "tags": ["travel", "photography", "food"]
}

Single Subfield

Configuration example:

yaml
- name: authors
  label: Authors
  widget: list
  field:
    name: author
    label: Author
    widget: string
toml
[[fields]]
name = "authors"
label = "Authors"
widget = "list"
[field]
name = "author"
label = "Author"
widget = "string"
json
{
  "name": "authors",
  "label": "Authors",
  "widget": "list",
  "field": {
    "name": "author",
    "label": "Author",
    "widget": "string"
  }
}
js
{
  name: "authors",
  label: "Authors",
  widget: "list",
  field: {
    name: "author",
    label: "Author",
    widget: "string",
  },
}

Output example:

yaml
authors:
  - Alice
  - Bob
  - Charlie
toml
authors = ["Alice", "Bob", "Charlie"]
json
{
  "authors": ["Alice", "Bob", "Charlie"]
}

Note that the name of the subfield will not appear in the output; only the values will be included in the list, just like a simple list.

Multiple Subfields

Configuration example:

yaml
- name: team_members
  label: Team Members
  widget: list
  fields:
    - name: name
      label: Name
      widget: string
    - name: role
      label: Role
      widget: string
toml
[[fields]]
name = "team_members"
label = "Team Members"
widget = "list"
[[fields.fields]]
name = "name"
label = "Name"
widget = "string"
[[fields.fields]]
name = "role"
label = "Role"
widget = "string"
json
{
  "name": "team_members",
  "label": "Team Members",
  "widget": "list",
  "fields": [
    {
      "name": "name",
      "label": "Name",
      "widget": "string"
    },
    {
      "name": "role",
      "label": "Role",
      "widget": "string"
    }
  ]
}
js
{
  name: "team_members",
  label: "Team Members",
  widget: "list",
  fields: [
    {
      name: "name",
      label: "Name",
      widget: "string",
    },
    {
      name: "role",
      label: "Role",
      widget: "string",
    },
  ],
}

Output example:

yaml
team_members:
  - name: Alice
    role: Developer
  - name: Bob
    role: Designer
  - name: Charlie
    role: Product Manager
toml
[[team_members]]
name = "Alice"
role = "Developer"

[[team_members]]
name = "Bob"
role = "Designer"

[[team_members]]
name = "Charlie"
role = "Product Manager"
json
{
  "team_members": [
    {
      "name": "Alice",
      "role": "Developer"
    },
    {
      "name": "Bob",
      "role": "Designer"
    },
    {
      "name": "Charlie",
      "role": "Product Manager"
    }
  ]
}

Using Summary and Thumbnail

Configuration example:

yaml
- name: projects
  label: Projects
  widget: list
  summary: "{{name}} - {{status}}"
  thumbnail: "image"
  fields:
    - name: name
      label: Name
      widget: string
    - name: status
      label: Status
      widget: string
    - name: image
      label: Image
      widget: image
toml
[[fields]]
name = "projects"
label = "Projects"
widget = "list"
summary = "{{name}} - {{status}}"
thumbnail = "image"
[[fields.fields]]
name = "name"
label = "Name"
widget = "string"
[[fields.fields]]
name = "status"
label = "Status"
widget = "string"
[[fields.fields]]
name = "image"
label = "Image"
widget = "image"
json
{
  "name": "projects",
  "label": "Projects",
  "widget": "list",
  "summary": "{{name}} - {{status}}",
  "thumbnail": "image",
  "fields": [
    {
      "name": "name",
      "label": "Name",
      "widget": "string"
    },
    {
      "name": "status",
      "label": "Status",
      "widget": "string"
    },
    {
      "name": "image",
      "label": "Image",
      "widget": "image"
    }
  ]
}
js
{
  name: "projects",
  label: "Projects",
  widget: "list",
  summary: "{{name}} - {{status}}",
  thumbnail: "image",
  fields: [
    {
      name: "name",
      label: "Name",
      widget: "string",
    },
    {
      name: "status",
      label: "Status",
      widget: "string",
    },
    {
      name: "image",
      label: "Image",
      widget: "image",
    },
  ],
}

Variable Type

The following example defines a variable type List field named items with two types: text_item and image_item. User can add either type of item to the list. These types can be mixed in any order.

yaml
- name: items
  label: Items
  widget: list
  types:
    - name: text_item
      label: Text Item
      fields:
        - name: text
          label: Text
          widget: string
    - name: image_item
      label: Image Item
      fields:
        - name: url
          label: Image URL
          widget: image
        - name: caption
          label: Caption
          widget: string
toml
[[fields]]
name = "items"
label = "Items"
widget = "list"
[[fields.types]]
label = "Text Item"
name = "text_item"
[[fields.types.fields]]
name = "text"
label = "Text"
widget = "string"
[[fields.types]]
label = "Image Item"
name = "image_item"
[[fields.types.fields]]
name = "url"
label = "Image URL"
widget = "image"
[[fields.types.fields]]
name = "caption"
label = "Caption"
widget = "string"
json
{
  "name": "items",
  "label": "Items",
  "widget": "list",
  "types": [
    {
      "label": "Text Item",
      "name": "text_item",
      "fields": [
        {
          "name": "text",
          "label": "Text",
          "widget": "string"
        }
      ]
    },
    {
      "label": "Image Item",
      "name": "image_item",
      "fields": [
        {
          "name": "url",
          "label": "Image URL",
          "widget": "image"
        },
        {
          "name": "caption",
          "label": "Caption",
          "widget": "string"
        }
      ]
    }
  ]
}
js
{
  name: "items",
  label: "Items",
  widget: "list",
  types: [
    {
      label: "Text Item",
      name: "text_item",
      fields: [
        {
          name: "text",
          label: "Text",
          widget: "string",
        },
      ],
    },
    {
      label: "Image Item",
      name: "image_item",
      fields: [
        {
          name: "url",
          label: "Image URL",
          widget: "image",
        },
        {
          name: "caption",
          label: "Caption",
          widget: "string",
        },
      ],
    },
  ],
}

Output example:

yaml
items:
  - type: text_item
    text: This is a text item.
  - type: image_item
    url: https://example.com/image.jpg
    caption: An example image.
  - type: text_item
    text: Another text item.
toml
[[items]]
type = "text_item"
text = "This is a text item."

[[items]]
type = "image_item"
url = "https://example.com/image.jpg"
caption = "An example image."

[[items]]
type = "text_item"
text = "Another text item."
json
{
  "items": [
    {
      "type": "text_item",
      "text": "This is a text item."
    },
    {
      "type": "image_item",
      "url": "https://example.com/image.jpg",
      "caption": "An example image."
    },
    {
      "type": "text_item",
      "text": "Another text item."
    }
  ]
}

Variable Type with Nested List

The following example defines a variable type List field named sections with two types: text_section and image_gallery. The image_gallery type contains a nested List field for multiple images.

TIP

You cannot have a List field directly under the types option; it must be nested within a type Object field, as shown in this example.

yaml
- name: sections
  label: Sections
  widget: list
  types:
    - name: text_section
      label: Text Section
      fields:
        - name: heading
          label: Heading
          widget: string
        - name: body
          label: Body
          widget: text
    - name: image_gallery
      label: Image Gallery
      fields:
        - name: title
          label: Title
          widget: string
        - name: images
          label: Images
          widget: list
          fields:
            - name: src
              label: Image URL
              widget: image
            - name: alt
              label: Alt Text
              widget: string
toml
[[fields]]
name = "sections"
label = "Sections"
widget = "list"
[[fields.types]]
name = "text_section"
label = "Text Section"
[[fields.types.fields]]
name = "heading"
label = "Heading"
widget = "string"
[[fields.types.fields]]
name = "body"
label = "Body"
widget = "text"
[[fields.types]]
name = "image_gallery"
label = "Image Gallery"
[[fields.types.fields]]
name = "title"
label = "Title"
widget = "string"
[[fields.types.fields]]
name = "images"
label = "Images"
widget = "list"
[[fields.types.fields.fields]]
name = "src"
label = "Image URL"
widget = "image"
[[fields.types.fields.fields]]
name = "alt"
label = "Alt Text"
widget = "string"
json
{
  "name": "sections",
  "label": "Sections",
  "widget": "list",
  "types": [
    {
      "name": "text_section",
      "label": "Text Section",
      "fields": [
        {
          "name": "heading",
          "label": "Heading",
          "widget": "string"
        },
        {
          "name": "body",
          "label": "Body",
          "widget": "text"
        }
      ]
    },
    {
      "name": "image_gallery",
      "label": "Image Gallery",
      "fields": [
        {
          "name": "title",
          "label": "Title",
          "widget": "string"
        },
        {
          "name": "images",
          "label": "Images",
          "widget": "list",
          "fields": [
            {
              "name": "src",
              "label": "Image URL",
              "widget": "image"
            },
            {
              "name": "alt",
              "label": "Alt Text",
              "widget": "string"
            }
          ]
        }
      ]
    }
  ]
}
js
{
  name: "sections",
  label: "Sections",
  widget: "list",
  types: [
    {
      name: "text_section",
      label: "Text Section",
      fields: [
        {
          name: "heading",
          label: "Heading",
          widget: "string",
        },
        {
          name: "body",
          label: "Body",
          widget: "text",
        },
      ],
    },
    {
      name: "image_gallery",
      label: "Image Gallery",
      fields: [
        {
          name: "title",
          label: "Title",
          widget: "string",
        },
        {
          name: "images",
          label: "Images",
          widget: "list",
          fields: [
            {
              name: "src",
              label: "Image URL",
              widget: "image",
            },
            {
              name: "alt",
              label: "Alt Text",
              widget: "string",
            },
          ],
        },
      ],
    },
  ],
}

Output example:

yaml
sections:
  - type: text_section
    heading: Welcome to Our Site
    body: This is the first section of our site.
  - type: image_gallery
    title: Our Gallery
    images:
      - src: https://example.com/image1.jpg
        alt: Image 1
      - src: https://example.com/image2.jpg
        alt: Image 2
toml
[[sections]]
type = "text_section"
heading = "Welcome to Our Site"
body = "This is the first section of our site."
[[sections]]
type = "image_gallery"
title = "Our Gallery"
[[sections.images]]
src = "https://example.com/image1.jpg"
alt = "Image 1"
[[sections.images]]
src = "https://example.com/image2.jpg"
alt = "Image 2"
json
{
  "sections": [
    {
      "type": "text_section",
      "heading": "Welcome to Our Site",
      "body": "This is the first section of our site."
    },
    {
      "type": "image_gallery",
      "title": "Our Gallery",
      "images": [
        {
          "src": "https://example.com/image1.jpg",
          "alt": "Image 1"
        },
        {
          "src": "https://example.com/image2.jpg",
          "alt": "Image 2"
        }
      ]
    }
  ]
}

Variable Type with Custom Type Key

By default, the type field is named type, but you can customize it using the typeKey option. Also, the fields option can be omitted if a type has no subfields.

The following example shows a simple page builder configuration with three block types: Heading, Paragraph, and Horizontal Rule.

yaml
- name: blocks
  label: Blocks
  widget: list
  typeKey: tag
  types:
    - name: h2
      label: Heading
      fields:
        - name: text
          label: Text
          widget: string
    - name: p
      label: Paragraph
      fields:
        - name: text
          label: Text
          widget: string
    - name: hr
      label: Horizontal Rule
toml
[[fields]]
name = "blocks"
label = "Blocks"
widget = "list"
typeKey = "tag"
[[fields.types]]
name = "h2"
label = "Heading"
[[fields.types.fields]]
name = "text"
label = "Text"
widget = "string"
[[fields.types]]
name = "p"
label = "Paragraph"
[[fields.types.fields]]
name = "text"
label = "Text"
widget = "string"
[[fields.types]]
name = "hr"
label = "Horizontal Rule"
json
{
  "name": "blocks",
  "label": "Blocks",
  "widget": "list",
  "typeKey": "tag",
  "types": [
    {
      "name": "h2",
      "label": "Heading",
      "fields": [
        {
          "name": "text",
          "label": "Text",
          "widget": "string"
        }
      ]
    },
    {
      "name": "p",
      "label": "Paragraph",
      "fields": [
        {
          "name": "text",
          "label": "Text",
          "widget": "string"
        }
      ]
    },
    {
      "name": "hr",
      "label": "Horizontal Rule"
    }
  ]
}
js
{
  name: "blocks",
  label: "Blocks",
  widget: "list",
  typeKey: "tag",
  types: [
    {
      name: "h2",
      label: "Heading",
      fields: [
        {
          name: "text",
          label: "Text",
          widget: "string",
        },
      ],
    },
    {
      name: "p",
      label: "Paragraph",
      fields: [
        {
          name: "text",
          label: "Text",
          widget: "string",
        },
      ],
    },
    {
      name: "hr",
      label: "Horizontal Rule",
    },
  ],
}

Output example:

yaml
blocks:
  - tag: h2
    text: Welcome to Our Site
  - tag: p
    text: This is the first paragraph of the site.
  - tag: hr
  - tag: p
    text: This is another paragraph after the horizontal rule.
toml
[[blocks]]
tag = "h2"
text = "Welcome to Our Site"
[[blocks]]
tag = "p"
text = "This is the first paragraph of the site."
[[blocks]]
tag = "hr"
[[blocks]]
tag = "p"
text = "This is another paragraph after the horizontal rule."
json
{
  "blocks": [
    {
      "tag": "h2",
      "text": "Welcome to Our Site"
    },
    {
      "tag": "p",
      "text": "This is the first paragraph of the site."
    },
    {
      "tag": "hr"
    },
    {
      "tag": "p",
      "text": "This is another paragraph after the horizontal rule."
    }
  ]
}

Top-Level List

It’s possible to define a List field at the top level of an output file, using the root option. The configuration below reproduces this Jekyll data file example:

yaml
collections:
  - name: data
    label: Data Files
    files:
      - name: members
        label: Member List
        file: _data/members.yml
        icon: group
        fields:
          - name: members
            label: Members
            label_singular: Member
            widget: list
            root: true
            fields:
              - name: name
                label: Name
              - name: github
                label: GitHub account
toml
[[collections]]
name = "data"
label = "Data Files"
[[collections.files]]
name = "members"
label = "Member List"
file = "_data/members.yml"
icon = "group"
[[collections.files.fields]]
name = "members"
label = "Members"
label_singular = "Member"
widget = "list"
root = true
[[collections.files.fields.fields]]
name = "name"
label = "Name"
[[collections.files.fields.fields]]
name = "github"
label = "GitHub account"
json
{
  "collections": [
    {
      "name": "data",
      "label": "Data Files",
      "files": [
        {
          "name": "members",
          "label": "Member List",
          "file": "_data/members.yml",
          "icon": "group",
          "fields": [
            {
              "name": "members",
              "label": "Members",
              "label_singular": "Member",
              "widget": "list",
              "root": true,
              "fields": [
                {
                  "name": "name",
                  "label": "Name"
                },
                {
                  "name": "github",
                  "label": "GitHub account"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "data",
      label: "Data Files",
      files: [
        {
          name: "members",
          label: "Member List",
          file: "_data/members.yml",
          icon: "group",
          fields: [
            {
              name: "members",
              label: "Members",
              label_singular: "Member",
              widget: "list",
              root: true,
              fields: [
                {
                  name: "name",
                  label: "Name",
                },
                {
                  name: "github",
                  label: "GitHub account",
                },
              ],
            },
          ],
        },
      ],
    },
  ],
}

It also works with a singleton. The configuration below reproduces the same data file example using a singleton:

yaml
singletons:
  - name: members
    label: Member List
    file: _data/members.yml
    icon: group
    fields:
      - name: members
        label: Members
        label_singular: Member
        widget: list
        root: true
        fields:
          - name: name
            label: Name
          - name: github
            label: GitHub account
toml
[[singletons]]
name = "members"
label = "Member List"
file = "_data/members.yml"
icon = "group"
[[singletons.fields]]
name = "members"
label = "Members"
label_singular = "Member"
widget = "list"
root = true
[[singletons.fields.fields]]
name = "name"
label = "Name"
[[singletons.fields.fields]]
name = "github"
label = "GitHub account"
json
{
  "singletons": [
    {
      "name": "members",
      "label": "Member List",
      "file": "_data/members.yml",
      "icon": "group",
      "fields": [
        {
          "name": "members",
          "label": "Members",
          "label_singular": "Member",
          "widget": "list",
          "root": true,
          "fields": [
            {
              "name": "name",
              "label": "Name"
            },
            {
              "name": "github",
              "label": "GitHub account"
            }
          ]
        }
      ]
    }
  ]
}
js
{
  singletons: [
    {
      name: "members",
      label: "Member List",
      file: "_data/members.yml",
      icon: "group",
      fields: [
        {
          name: "members",
          label: "Members",
          label_singular: "Member",
          widget: "list",
          root: true,
          fields: [
            {
              name: "name",
              label: "Name",
            },
            {
              name: "github",
              label: "GitHub account",
            },
          ],
        },
      ],
    },
  ],
}

Output example:

yaml
- name: Alice
  github: alicehub123
- name: Bob
  github: bobgit456
- name: Charlie
  github: charliecode789
json
[
  {
    "name": "Alice",
    "github": "alicehub123"
  },
  {
    "name": "Bob",
    "github": "bobgit456"
  },
  {
    "name": "Charlie",
    "github": "charliecode789"
  }
]

As you can see, the list is stored directly at the root level of the output file, without a parent key (members). We don’t have a TOML example here because TOML format cannot represent top-level arrays; thus, the root option is ignored for TOML files.

Released under the MIT License.